From 2dd0cb7aeb2d70dcc6e103c29ce2ce3a02bd381a Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 20 Feb 2019 11:35:47 -0500 Subject: Help: note that Ninja also uses OBJECT_OUTPUTS --- Help/prop_sf/OBJECT_OUTPUTS.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Help/prop_sf/OBJECT_OUTPUTS.rst b/Help/prop_sf/OBJECT_OUTPUTS.rst index 6a28553..1ce4866 100644 --- a/Help/prop_sf/OBJECT_OUTPUTS.rst +++ b/Help/prop_sf/OBJECT_OUTPUTS.rst @@ -1,9 +1,9 @@ OBJECT_OUTPUTS -------------- -Additional outputs for a Makefile rule. +Additional outputs for a Ninja or Makefile rule. Additional outputs created by compilation of this source file. If any of these outputs is missing the object will be recompiled. This is -supported only on Makefile generators and will be ignored on other -generators. +supported only on the Ninja and Makefile generators and will be ignored on +other generators. -- cgit v0.12 From 72f9bb29939f3765216e98e672197b3899d75f7d Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 20 Feb 2019 01:39:55 -0500 Subject: ninja: make dyndep generation language aware A target may have multiple languages with dyndep rules, separate `.dd` files should be generated. --- Source/cmGlobalNinjaGenerator.cxx | 31 ++++++++++++++++++++----------- Source/cmGlobalNinjaGenerator.h | 3 ++- Source/cmNinjaTargetGenerator.cxx | 21 ++++++++++++--------- Source/cmNinjaTargetGenerator.h | 3 ++- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 018606c..5a85963 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -1593,7 +1593,7 @@ Compilation of source files within a target is split into the following steps: rule Fortran_DYNDEP command = cmake -E cmake_ninja_dyndep \ - --tdi=FortranDependInfo.json --dd=$out $in + --tdi=FortranDependInfo.json --lang=Fortran --dd=$out $in build Fortran.dd: Fortran_DYNDEP src1.f90-pp.f90.ddi src2.f90-pp.f90.ddi @@ -1755,7 +1755,7 @@ int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, return 0; } -struct cmFortranObjectInfo +struct cmDyndepObjectInfo { std::string Object; std::vector Provides; @@ -1767,7 +1767,8 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( std::string const& dir_cur_src, std::string const& dir_cur_bld, std::string const& arg_dd, std::vector const& arg_ddis, std::string const& module_dir, - std::vector const& linked_target_dirs) + std::vector const& linked_target_dirs, + std::string const& arg_lang) { // Setup path conversions. { @@ -1784,7 +1785,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( this->LocalGenerators.push_back(lgd.release()); } - std::vector objects; + std::vector objects; for (std::string const& arg_ddi : arg_ddis) { // Load the ddi file and compute the module file paths it provides. Json::Value ddio; @@ -1797,7 +1798,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( return false; } - cmFortranObjectInfo info; + cmDyndepObjectInfo info; info.Object = ddi["object"].asString(); Json::Value const& ddi_provides = ddi["provides"]; if (ddi_provides.isArray()) { @@ -1819,7 +1820,8 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( // Populate the module map with those provided by linked targets first. for (std::string const& linked_target_dir : linked_target_dirs) { - std::string const ltmn = linked_target_dir + "/FortranModules.json"; + std::string const ltmn = + linked_target_dir + "/" + arg_lang + "Modules.json"; Json::Value ltm; cmsys::ifstream ltmf(ltmn.c_str(), std::ios::in | std::ios::binary); Json::Reader reader; @@ -1840,7 +1842,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( // We do this after loading the modules provided by linked targets // in case we have one of the same name that must be preferred. Json::Value tm = Json::objectValue; - for (cmFortranObjectInfo const& object : objects) { + for (cmDyndepObjectInfo const& object : objects) { for (std::string const& p : object.Provides) { std::string const mod = module_dir + p; mod_files[p] = mod; @@ -1851,7 +1853,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( cmGeneratedFileStream ddf(arg_dd); ddf << "ninja_dyndep_version = 1.0\n"; - for (cmFortranObjectInfo const& object : objects) { + for (cmDyndepObjectInfo const& object : objects) { std::string const ddComment; std::string const ddRule = "dyndep"; cmNinjaDeps ddOutputs; @@ -1882,7 +1884,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( // Store the map of modules provided by this target in a file for // use by dependents that reference this target in linked-target-dirs. std::string const target_mods_file = - cmSystemTools::GetFilenamePath(arg_dd) + "/FortranModules.json"; + cmSystemTools::GetFilenamePath(arg_dd) + "/" + arg_lang + "Modules.json"; cmGeneratedFileStream tmf(target_mods_file); tmf << tm; @@ -1896,11 +1898,14 @@ int cmcmd_cmake_ninja_dyndep(std::vector::const_iterator argBeg, cmSystemTools::HandleResponseFile(argBeg, argEnd); std::string arg_dd; + std::string arg_lang; std::string arg_tdi; std::vector arg_ddis; for (std::string const& arg : arg_full) { if (cmHasLiteralPrefix(arg, "--tdi=")) { arg_tdi = arg.substr(6); + } else if (cmHasLiteralPrefix(arg, "--lang=")) { + arg_lang = arg.substr(7); } else if (cmHasLiteralPrefix(arg, "--dd=")) { arg_dd = arg.substr(5); } else if (!cmHasLiteralPrefix(arg, "--") && @@ -1915,6 +1920,10 @@ int cmcmd_cmake_ninja_dyndep(std::vector::const_iterator argBeg, cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --tdi="); return 1; } + if (arg_lang.empty()) { + cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --lang="); + return 1; + } if (arg_dd.empty()) { cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --dd="); return 1; @@ -1955,8 +1964,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector::const_iterator argBeg, static_cast(cm.CreateGlobalGenerator("Ninja"))); if (!ggd || !ggd->WriteDyndepFile(dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, - arg_dd, arg_ddis, module_dir, - linked_target_dirs)) { + arg_dd, arg_ddis, module_dir, linked_target_dirs, + arg_lang)) { return 1; } return 0; diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index c619e67..69210ec 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -365,7 +365,8 @@ public: std::string const& arg_dd, std::vector const& arg_ddis, std::string const& module_dir, - std::vector const& linked_target_dirs); + std::vector const& linked_target_dirs, + std::string const& arg_lang); protected: void Generate() override; diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 6013cd0..6a08d5c 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -594,7 +594,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) ddCmds.push_back(cmake + " -E cmake_ninja_dyndep" " --tdi=" + - tdi + + tdi + " --lang=" + lang + " --dd=$out" " " + ddInput); @@ -868,24 +868,27 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements() this->WriteObjectBuildStatement(sf); } - if (!this->DDIFiles.empty()) { + for (auto const& langDDIFiles : this->DDIFiles) { + std::string const& language = langDDIFiles.first; + cmNinjaDeps const& ddiFiles = langDDIFiles.second; + std::string const ddComment; - std::string const ddRule = this->LanguageDyndepRule("Fortran"); + std::string const ddRule = this->LanguageDyndepRule(language); cmNinjaDeps ddOutputs; cmNinjaDeps ddImplicitOuts; - cmNinjaDeps const& ddExplicitDeps = this->DDIFiles; + cmNinjaDeps const& ddExplicitDeps = ddiFiles; cmNinjaDeps ddImplicitDeps; cmNinjaDeps ddOrderOnlyDeps; cmNinjaVars ddVars; - this->WriteTargetDependInfo("Fortran"); + this->WriteTargetDependInfo(language); - ddOutputs.push_back(this->GetDyndepFilePath("Fortran")); + ddOutputs.push_back(this->GetDyndepFilePath(language)); // Make sure dyndep files for all our dependencies have already - // been generated so that the 'FortranModules.json' files they + // been generated so that the 'Modules.json' files they // produced as side-effects are available for us to read. - // Ideally we should depend on the 'FortranModules.json' files + // Ideally we should depend on the 'Modules.json' files // from our dependencies directly, but we don't know which of // our dependencies produces them. Fixing this will require // refactoring the Ninja generator to generate targets in @@ -1099,7 +1102,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( std::string const ddiFile = ppFileName + ".ddi"; ppVars["DYNDEP_INTERMEDIATE_FILE"] = ddiFile; ppImplicitOuts.push_back(ddiFile); - this->DDIFiles.push_back(ddiFile); + this->DDIFiles[language].push_back(ddiFile); } this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(), diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 373c693..2ffd256 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -10,6 +10,7 @@ #include "cmNinjaTypes.h" #include "cmOSXBundleGenerator.h" +#include #include #include #include @@ -165,7 +166,7 @@ private: cmLocalNinjaGenerator* LocalGenerator; /// List of object files for this target. cmNinjaDeps Objects; - cmNinjaDeps DDIFiles; // TODO: Make per-language. + std::map DDIFiles; std::vector CustomCommands; cmNinjaDeps ExtraFiles; }; -- cgit v0.12 From 2c0a7bc770367e80ce1fc68ea6cb9c9543e854e4 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 20 Feb 2019 04:57:07 -0500 Subject: ninja: pass language to cmake_ninja_depends --- Source/cmGlobalNinjaGenerator.cxx | 119 ++++++++++++++++++++++++++------------ Source/cmNinjaTargetGenerator.cxx | 6 +- 2 files changed, 85 insertions(+), 40 deletions(-) diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 5a85963..74d3e8d 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -1574,7 +1574,8 @@ Compilation of source files within a target is split into the following steps: command = gfortran -cpp $DEFINES $INCLUDES $FLAGS -E $in -o $out && cmake -E cmake_ninja_depends \ --tdi=FortranDependInfo.json --pp=$out --dep=$DEP_FILE \ - --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE + --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE \ + --lang=Fortran build src.f90-pp.f90 | src.f90-pp.f90.ddi: Fortran_PREPROCESS src.f90 OBJ_FILE = src.f90.o @@ -1633,6 +1634,19 @@ Compilation of source files within a target is split into the following steps: (because the latter consumes the module). */ +struct cmSourceInfo +{ + // Set of provided and required modules. + std::set Provides; + std::set Requires; + + // Set of files included in the translation unit. + std::set Includes; +}; + +static std::unique_ptr cmcmd_cmake_ninja_depends_fortran( + std::string const& arg_tdi, std::string const& arg_pp); + int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, std::vector::const_iterator argEnd) { @@ -1641,6 +1655,7 @@ int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, std::string arg_dep; std::string arg_obj; std::string arg_ddi; + std::string arg_lang; for (std::string const& arg : cmMakeRange(argBeg, argEnd)) { if (cmHasLiteralPrefix(arg, "--tdi=")) { arg_tdi = arg.substr(6); @@ -1652,6 +1667,8 @@ int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, arg_obj = arg.substr(6); } else if (cmHasLiteralPrefix(arg, "--ddi=")) { arg_ddi = arg.substr(6); + } else if (cmHasLiteralPrefix(arg, "--lang=")) { + arg_lang = arg.substr(7); } else { cmSystemTools::Error("-E cmake_ninja_depends unknown argument: " + arg); return 1; @@ -1677,7 +1694,61 @@ int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, cmSystemTools::Error("-E cmake_ninja_depends requires value for --ddi="); return 1; } + if (arg_lang.empty()) { + cmSystemTools::Error("-E cmake_ninja_depends requires value for --lang="); + return 1; + } + + std::unique_ptr info; + if (arg_lang == "Fortran") { + info = cmcmd_cmake_ninja_depends_fortran(arg_tdi, arg_pp); + } else { + cmSystemTools::Error("-E cmake_ninja_depends does not understand the " + + arg_lang + " language"); + return 1; + } + if (!info) { + // The error message is already expected to have been output. + return 1; + } + + { + cmGeneratedFileStream depfile(arg_dep); + depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":"; + for (std::string const& include : info->Includes) { + depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(include); + } + depfile << "\n"; + } + + Json::Value ddi(Json::objectValue); + ddi["object"] = arg_obj; + + Json::Value& ddi_provides = ddi["provides"] = Json::arrayValue; + for (std::string const& provide : info->Provides) { + ddi_provides.append(provide); + } + Json::Value& ddi_requires = ddi["requires"] = Json::arrayValue; + for (std::string const& r : info->Requires) { + // Require modules not provided in the same source. + if (!info->Provides.count(r)) { + ddi_requires.append(r); + } + } + + cmGeneratedFileStream ddif(arg_ddi); + ddif << ddi; + if (!ddif) { + cmSystemTools::Error("-E cmake_ninja_depends failed to write " + arg_ddi); + return 1; + } + return 0; +} + +std::unique_ptr cmcmd_cmake_ninja_depends_fortran( + std::string const& arg_tdi, std::string const& arg_pp) +{ cmFortranCompiler fc; std::vector includes; { @@ -1689,7 +1760,7 @@ int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, if (!reader.parse(tdif, tdio, false)) { cmSystemTools::Error("-E cmake_ninja_depends failed to parse " + arg_tdi + reader.getFormattedErrorMessages()); - return 1; + return nullptr; } } @@ -1710,49 +1781,23 @@ int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, fc.SModExt = tdi_submodule_ext.asString(); } - cmFortranSourceInfo info; + cmFortranSourceInfo finfo; std::set defines; - cmFortranParser parser(fc, includes, defines, info); + cmFortranParser parser(fc, includes, defines, finfo); if (!cmFortranParser_FilePush(&parser, arg_pp.c_str())) { cmSystemTools::Error("-E cmake_ninja_depends failed to open " + arg_pp); - return 1; + return nullptr; } if (cmFortran_yyparse(parser.Scanner) != 0) { // Failed to parse the file. - return 1; - } - - { - cmGeneratedFileStream depfile(arg_dep); - depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":"; - for (std::string const& include : info.Includes) { - depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(include); - } - depfile << "\n"; + return nullptr; } - Json::Value ddi(Json::objectValue); - ddi["object"] = arg_obj; - - Json::Value& ddi_provides = ddi["provides"] = Json::arrayValue; - for (std::string const& provide : info.Provides) { - ddi_provides.append(provide); - } - Json::Value& ddi_requires = ddi["requires"] = Json::arrayValue; - for (std::string const& r : info.Requires) { - // Require modules not provided in the same source. - if (!info.Provides.count(r)) { - ddi_requires.append(r); - } - } - - cmGeneratedFileStream ddif(arg_ddi); - ddif << ddi; - if (!ddif) { - cmSystemTools::Error("-E cmake_ninja_depends failed to write " + arg_ddi); - return 1; - } - return 0; + auto info = cm::make_unique(); + info->Provides = finfo.Provides; + info->Requires = finfo.Requires; + info->Includes = finfo.Includes; + return info; } struct cmDyndepObjectInfo diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 6a08d5c..28d4a07 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -558,7 +558,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) cmake + " -E cmake_ninja_depends" " --tdi=" + - tdi + + tdi + " --lang=" + lang + " --pp=$out" " --dep=$DEP_FILE" + (needDyndep ? " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE" : "")); @@ -1062,8 +1062,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( // In case compilation requires flags that are incompatible with // preprocessing, include them here. - std::string const postFlag = - this->Makefile->GetSafeDefinition("CMAKE_Fortran_POSTPROCESS_FLAG"); + std::string const postFlag = this->Makefile->GetSafeDefinition( + "CMAKE_" + language + "_POSTPROCESS_FLAG"); this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag); // Move preprocessor definitions to the preprocessor build statement. -- cgit v0.12 From 933dd9164210a2f08dae6e1333ab7e5c30e3b012 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 20 Feb 2019 12:13:33 -0500 Subject: ninja: do not assume explicit preprocessing uses that output In Fortran, this is OK, but for C++, compiling preprocessed source generally results in poorer diagnostic messages and can also be ill-formed anyways. --- Source/cmNinjaTargetGenerator.cxx | 78 ++++++++++++++++++++++++++------------- Source/cmNinjaTargetGenerator.h | 1 + 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 28d4a07..4998ac8 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -102,6 +102,12 @@ bool cmNinjaTargetGenerator::NeedExplicitPreprocessing( return lang == "Fortran"; } +bool cmNinjaTargetGenerator::UsePreprocessedSource( + std::string const& lang) const +{ + return lang == "Fortran"; +} + std::string cmNinjaTargetGenerator::LanguageDyndepRule( const std::string& lang) const { @@ -1035,6 +1041,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( // For some cases we do an explicit preprocessor invocation. bool const explicitPP = this->NeedExplicitPreprocessing(language); if (explicitPP) { + bool const compilePP = this->UsePreprocessedSource(language); std::string const ppComment; std::string const ppRule = this->LanguagePreprocessRule(language); cmNinjaDeps ppOutputs; @@ -1048,50 +1055,69 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source)); ppOutputs.push_back(ppFileName); - // Move compilation dependencies to the preprocessing build statement. - std::swap(ppExplicitDeps, explicitDeps); - std::swap(ppImplicitDeps, implicitDeps); - std::swap(ppOrderOnlyDeps, orderOnlyDeps); - std::swap(ppVars["IN_ABS"], vars["IN_ABS"]); + if (compilePP) { + // Move compilation dependencies to the preprocessing build statement. + std::swap(ppExplicitDeps, explicitDeps); + std::swap(ppImplicitDeps, implicitDeps); + std::swap(ppOrderOnlyDeps, orderOnlyDeps); + std::swap(ppVars["IN_ABS"], vars["IN_ABS"]); - // The actual compilation will now use the preprocessed source. - explicitDeps.push_back(ppFileName); + // The actual compilation will now use the preprocessed source. + explicitDeps.push_back(ppFileName); + } else { + // Copy compilation dependencies to the preprocessing build statement. + ppExplicitDeps = explicitDeps; + ppImplicitDeps = implicitDeps; + ppOrderOnlyDeps = orderOnlyDeps; + ppVars["IN_ABS"] = vars["IN_ABS"]; + } // Preprocessing and compilation generally use the same flags. ppVars["FLAGS"] = vars["FLAGS"]; - // In case compilation requires flags that are incompatible with - // preprocessing, include them here. - std::string const postFlag = this->Makefile->GetSafeDefinition( - "CMAKE_" + language + "_POSTPROCESS_FLAG"); - this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag); + if (compilePP) { + // In case compilation requires flags that are incompatible with + // preprocessing, include them here. + std::string const postFlag = this->Makefile->GetSafeDefinition( + "CMAKE_" + language + "_POSTPROCESS_FLAG"); + this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag); + } - // Move preprocessor definitions to the preprocessor build statement. - std::swap(ppVars["DEFINES"], vars["DEFINES"]); + if (compilePP) { + // Move preprocessor definitions to the preprocessor build statement. + std::swap(ppVars["DEFINES"], vars["DEFINES"]); + } else { + // Copy preprocessor definitions to the preprocessor build statement. + ppVars["DEFINES"] = vars["DEFINES"]; + } // Copy include directories to the preprocessor build statement. The // Fortran compilation build statement still needs them for the INCLUDE // directive. ppVars["INCLUDES"] = vars["INCLUDES"]; - // Prepend source file's original directory as an include directory - // so e.g. Fortran INCLUDE statements can look for files in it. - std::vector sourceDirectory; - sourceDirectory.push_back( - cmSystemTools::GetParentDirectory(source->GetFullPath())); + if (compilePP) { + // Prepend source file's original directory as an include directory + // so e.g. Fortran INCLUDE statements can look for files in it. + std::vector sourceDirectory; + sourceDirectory.push_back( + cmSystemTools::GetParentDirectory(source->GetFullPath())); - std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags( - sourceDirectory, this->GeneratorTarget, language, false, false, - this->GetConfigName()); + std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags( + sourceDirectory, this->GeneratorTarget, language, false, false, + this->GetConfigName()); - vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"]; + vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"]; + } // Explicit preprocessing always uses a depfile. ppVars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( ppFileName + ".d", cmOutputConverter::SHELL); - // The actual compilation does not need a depfile because it - // depends on the already-preprocessed source. - vars.erase("DEP_FILE"); + if (compilePP) { + // The actual compilation does not need a depfile because it + // depends on the already-preprocessed source. + vars.erase("DEP_FILE"); + } if (needDyndep) { // Tell dependency scanner the object file that will result from diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 2ffd256..6a42da0 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -65,6 +65,7 @@ protected: bool NeedExplicitPreprocessing(std::string const& lang) const; std::string LanguageDyndepRule(std::string const& lang) const; bool NeedDyndep(std::string const& lang) const; + bool UsePreprocessedSource(std::string const& lang) const; std::string OrderDependsTargetForTarget(); -- cgit v0.12 From 7c78adca8e0285c198e03163c2bb722cd86b389d Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 20 Feb 2019 01:41:26 -0500 Subject: cmNinjaTargetGenerator: remove "preprocessed" mentions in dyndep Not all languages compile the preprocessed source (or even have preprocessed sources at all). --- Source/cmNinjaTargetGenerator.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 4998ac8..6e140fb 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -594,7 +594,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) std::string ddRspContent = "$in"; std::string ddInput = "@" + ddRspFile; - // Run CMake dependency scanner on preprocessed output. + // Run CMake dependency scanner on the source file (using the preprocessed + // source if that was performed). std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat( cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); ddCmds.push_back(cmake + @@ -1121,7 +1122,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( if (needDyndep) { // Tell dependency scanner the object file that will result from - // compiling the preprocessed source. + // compiling the source. ppVars["OBJ_FILE"] = objectFileName; // Tell dependency scanner where to store dyndep intermediate results. -- cgit v0.12 From f22c18b1c1554b573c684efcb5c921c17c9b0f1d Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 20 Feb 2019 13:20:28 -0500 Subject: ninja: name dyndep internal files using the object file Now that preprocessing outputs are not necessarily used all the way through, the output name is a better base name to use for these files. --- Source/cmGlobalNinjaGenerator.cxx | 8 ++++---- Source/cmNinjaTargetGenerator.cxx | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 74d3e8d..d21fd35 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -1577,10 +1577,10 @@ Compilation of source files within a target is split into the following steps: --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE \ --lang=Fortran - build src.f90-pp.f90 | src.f90-pp.f90.ddi: Fortran_PREPROCESS src.f90 + build src.f90-pp.f90 | src.f90.o.ddi: Fortran_PREPROCESS src.f90 OBJ_FILE = src.f90.o - DEP_FILE = src.f90-pp.f90.d - DYNDEP_INTERMEDIATE_FILE = src.f90-pp.f90.ddi + DEP_FILE = src.f90.o.d + DYNDEP_INTERMEDIATE_FILE = src.f90.o.ddi The ``cmake -E cmake_ninja_depends`` tool reads the preprocessed output and generates the ninja depfile for preprocessor dependencies. It also @@ -1596,7 +1596,7 @@ Compilation of source files within a target is split into the following steps: command = cmake -E cmake_ninja_dyndep \ --tdi=FortranDependInfo.json --lang=Fortran --dd=$out $in - build Fortran.dd: Fortran_DYNDEP src1.f90-pp.f90.ddi src2.f90-pp.f90.ddi + build Fortran.dd: Fortran_DYNDEP src1.f90.o.ddi src2.f90.o.ddi The ``cmake -E cmake_ninja_dyndep`` tool reads the "ddi" files from all sources in the target and the ``FortranModules.json`` files from targets diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 6e140fb..8d11408 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1113,7 +1113,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( // Explicit preprocessing always uses a depfile. ppVars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( - ppFileName + ".d", cmOutputConverter::SHELL); + objectFileName + ".d", cmOutputConverter::SHELL); if (compilePP) { // The actual compilation does not need a depfile because it // depends on the already-preprocessed source. @@ -1126,7 +1126,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( ppVars["OBJ_FILE"] = objectFileName; // Tell dependency scanner where to store dyndep intermediate results. - std::string const ddiFile = ppFileName + ".ddi"; + std::string const ddiFile = objectFileName + ".ddi"; ppVars["DYNDEP_INTERMEDIATE_FILE"] = ddiFile; ppImplicitOuts.push_back(ddiFile); this->DDIFiles[language].push_back(ddiFile); -- cgit v0.12 ********************* Copyright (C) 1997, 2002, 2003 Martin von Loewis Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies. This software comes with no warranty. Use at your own risk. ******************************************************************/ #include "Python.h" #include <stdio.h> #include <locale.h> #include <string.h> #include <ctype.h> #ifdef HAVE_ERRNO_H #include <errno.h> #endif #ifdef HAVE_LANGINFO_H #include <langinfo.h> #endif #ifdef HAVE_LIBINTL_H #include <libintl.h> #endif #ifdef HAVE_WCHAR_H #include <wchar.h> #endif #if defined(__APPLE__) #include <CoreFoundation/CoreFoundation.h> #endif #if defined(MS_WINDOWS) #define WIN32_LEAN_AND_MEAN #include <windows.h> #endif #ifdef RISCOS char *strdup(const char *); #endif PyDoc_STRVAR(locale__doc__, "Support for POSIX locales."); static PyObject *Error; /* support functions for formatting floating point numbers */ PyDoc_STRVAR(setlocale__doc__, "(integer,string=None) -> string. Activates/queries locale processing."); /* the grouping is terminated by either 0 or CHAR_MAX */ static PyObject* copy_grouping(char* s) { int i; PyObject *result, *val = NULL; if (s[0] == '\0') /* empty string: no grouping at all */ return PyList_New(0); for (i = 0; s[i] != '\0' && s[i] != CHAR_MAX; i++) ; /* nothing */ result = PyList_New(i+1); if (!result) return NULL; i = -1; do { i++; val = PyInt_FromLong(s[i]); if (!val) break; if (PyList_SetItem(result, i, val)) { Py_DECREF(val); val = NULL; break; } } while (s[i] != '\0' && s[i] != CHAR_MAX); if (!val) { Py_DECREF(result); return NULL; } return result; } static void fixup_ulcase(void) { PyObject *mods, *string, *ulo; unsigned char ul[256]; int n, c; /* find the string module */ mods = PyImport_GetModuleDict(); if (!mods) return; string = PyDict_GetItemString(mods, "string"); if (string) string = PyModule_GetDict(string); if (!string) return; /* create uppercase map string */ n = 0; for (c = 0; c < 256; c++) { if (isupper(c)) ul[n++] = c; } ulo = PyString_FromStringAndSize((const char *)ul, n); if (!ulo) return; if (string) PyDict_SetItemString(string, "uppercase", ulo); Py_DECREF(ulo); /* create lowercase string */ n = 0; for (c = 0; c < 256; c++) { if (islower(c)) ul[n++] = c; } ulo = PyString_FromStringAndSize((const char *)ul, n); if (!ulo) return; if (string) PyDict_SetItemString(string, "lowercase", ulo); Py_DECREF(ulo); /* create letters string */ n = 0; for (c = 0; c < 256; c++) { if (isalpha(c)) ul[n++] = c; } ulo = PyString_FromStringAndSize((const char *)ul, n); if (!ulo) return; if (string) PyDict_SetItemString(string, "letters", ulo); Py_DECREF(ulo); } static PyObject* PyLocale_setlocale(PyObject* self, PyObject* args) { int category; char *locale = NULL, *result; PyObject *result_object; if (!PyArg_ParseTuple(args, "i|z:setlocale", &category, &locale)) return NULL; if (locale) { /* set locale */ result = setlocale(category, locale); if (!result) { /* operation failed, no setting was changed */ PyErr_SetString(Error, "unsupported locale setting"); return NULL; } result_object = PyString_FromString(result); if (!result_object) return NULL; /* record changes to LC_CTYPE */ if (category == LC_CTYPE || category == LC_ALL) fixup_ulcase(); /* things that got wrong up to here are ignored */ PyErr_Clear(); } else { /* get locale */ result = setlocale(category, NULL); if (!result) { PyErr_SetString(Error, "locale query failed"); return NULL; } result_object = PyString_FromString(result); } return result_object; } PyDoc_STRVAR(localeconv__doc__, "() -> dict. Returns numeric and monetary locale-specific parameters."); static PyObject* PyLocale_localeconv(PyObject* self) { PyObject* result; struct lconv *l; PyObject *x; result = PyDict_New(); if (!result) return NULL; /* if LC_NUMERIC is different in the C library, use saved value */ l = localeconv(); /* hopefully, the localeconv result survives the C library calls involved herein */ #define RESULT_STRING(s)\ x = PyString_FromString(l->s);\ if (!x) goto failed;\ PyDict_SetItemString(result, #s, x);\ Py_XDECREF(x) #define RESULT_INT(i)\ x = PyInt_FromLong(l->i);\ if (!x) goto failed;\ PyDict_SetItemString(result, #i, x);\ Py_XDECREF(x) /* Numeric information */ RESULT_STRING(decimal_point); RESULT_STRING(thousands_sep); x = copy_grouping(l->grouping); if (!x) goto failed; PyDict_SetItemString(result, "grouping", x); Py_XDECREF(x); /* Monetary information */ RESULT_STRING(int_curr_symbol); RESULT_STRING(currency_symbol); RESULT_STRING(mon_decimal_point); RESULT_STRING(mon_thousands_sep); x = copy_grouping(l->mon_grouping); if (!x) goto failed; PyDict_SetItemString(result, "mon_grouping", x); Py_XDECREF(x); RESULT_STRING(positive_sign); RESULT_STRING(negative_sign); RESULT_INT(int_frac_digits); RESULT_INT(frac_digits); RESULT_INT(p_cs_precedes); RESULT_INT(p_sep_by_space); RESULT_INT(n_cs_precedes); RESULT_INT(n_sep_by_space); RESULT_INT(p_sign_posn); RESULT_INT(n_sign_posn); return result; failed: Py_XDECREF(result); Py_XDECREF(x); return NULL; } PyDoc_STRVAR(strcoll__doc__, "string,string -> int. Compares two strings according to the locale."); static PyObject* PyLocale_strcoll(PyObject* self, PyObject* args) { #if !defined(HAVE_WCSCOLL) char *s1,*s2; if (!PyArg_ParseTuple(args, "ss:strcoll", &s1, &s2)) return NULL; return PyInt_FromLong(strcoll(s1, s2)); #else PyObject *os1, *os2, *result = NULL; wchar_t *ws1 = NULL, *ws2 = NULL; int rel1 = 0, rel2 = 0, len1, len2; if (!PyArg_UnpackTuple(args, "strcoll", 2, 2, &os1, &os2)) return NULL; /* If both arguments are byte strings, use strcoll. */ if (PyString_Check(os1) && PyString_Check(os2)) return PyInt_FromLong(strcoll(PyString_AS_STRING(os1), PyString_AS_STRING(os2))); /* If neither argument is unicode, it's an error. */ if (!PyUnicode_Check(os1) && !PyUnicode_Check(os2)) { PyErr_SetString(PyExc_ValueError, "strcoll arguments must be strings"); } /* Convert the non-unicode argument to unicode. */ if (!PyUnicode_Check(os1)) { os1 = PyUnicode_FromObject(os1); if (!os1) return NULL; rel1 = 1; } if (!PyUnicode_Check(os2)) { os2 = PyUnicode_FromObject(os2); if (!os2) { Py_DECREF(os1); return NULL; } rel2 = 1; } /* Convert the unicode strings to wchar[]. */ len1 = PyUnicode_GET_SIZE(os1) + 1; ws1 = PyMem_MALLOC(len1 * sizeof(wchar_t)); if (!ws1) { PyErr_NoMemory(); goto done; } if (PyUnicode_AsWideChar((PyUnicodeObject*)os1, ws1, len1) == -1) goto done; ws1[len1 - 1] = 0; len2 = PyUnicode_GET_SIZE(os2) + 1; ws2 = PyMem_MALLOC(len2 * sizeof(wchar_t)); if (!ws2) { PyErr_NoMemory(); goto done; } if (PyUnicode_AsWideChar((PyUnicodeObject*)os2, ws2, len2) == -1) goto done; ws2[len2 - 1] = 0; /* Collate the strings. */ result = PyInt_FromLong(wcscoll(ws1, ws2)); done: /* Deallocate everything. */ if (ws1) PyMem_FREE(ws1); if (ws2) PyMem_FREE(ws2); if (rel1) { Py_DECREF(os1); } if (rel2) { Py_DECREF(os2); } return result; #endif } PyDoc_STRVAR(strxfrm__doc__, "string -> string. Returns a string that behaves for cmp locale-aware."); static PyObject* PyLocale_strxfrm(PyObject* self, PyObject* args) { char *s, *buf; size_t n1, n2; PyObject *result; if (!PyArg_ParseTuple(args, "s:strxfrm", &s)) return NULL; /* assume no change in size, first */ n1 = strlen(s) + 1; buf = PyMem_Malloc(n1); if (!buf) return PyErr_NoMemory(); n2 = strxfrm(buf, s, n1) + 1; if (n2 > n1) { /* more space needed */ buf = PyMem_Realloc(buf, n2); if (!buf) return PyErr_NoMemory(); strxfrm(buf, s, n2); } result = PyString_FromString(buf); PyMem_Free(buf); return result; } #if defined(MS_WINDOWS) static PyObject* PyLocale_getdefaultlocale(PyObject* self) { char encoding[100]; char locale[100]; PyOS_snprintf(encoding, sizeof(encoding), "cp%d", GetACP()); if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, locale, sizeof(locale))) { Py_ssize_t i = strlen(locale); locale[i++] = '_'; if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, locale+i, (int)(sizeof(locale)-i))) return Py_BuildValue("ss", locale, encoding); } /* If we end up here, this windows version didn't know about ISO639/ISO3166 names (it's probably Windows 95). Return the Windows language identifier instead (a hexadecimal number) */ locale[0] = '0'; locale[1] = 'x'; if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTLANGUAGE, locale+2, sizeof(locale)-2)) { return Py_BuildValue("ss", locale, encoding); } /* cannot determine the language code (very unlikely) */ Py_INCREF(Py_None); return Py_BuildValue("Os", Py_None, encoding); } #endif #if defined(__APPLE__) /* ** Find out what the current script is. ** Donated by Fredrik Lundh. */ static char *mac_getscript(void) { CFStringEncoding enc = CFStringGetSystemEncoding(); static CFStringRef name = NULL; /* Return the code name for the encodings for which we have codecs. */ switch(enc) { case kCFStringEncodingMacRoman: return "mac-roman"; case kCFStringEncodingMacGreek: return "mac-greek"; case kCFStringEncodingMacCyrillic: return "mac-cyrillic"; case kCFStringEncodingMacTurkish: return "mac-turkish"; case kCFStringEncodingMacIcelandic: return "mac-icelandic"; /* XXX which one is mac-latin2? */ } if (!name) { /* This leaks an object. */ name = CFStringConvertEncodingToIANACharSetName(enc); } return (char *)CFStringGetCStringPtr(name, 0); } static PyObject* PyLocale_getdefaultlocale(PyObject* self) { return Py_BuildValue("Os", Py_None, mac_getscript()); } #endif #ifdef HAVE_LANGINFO_H #define LANGINFO(X) {#X, X} struct langinfo_constant{ char* name; int value; } langinfo_constants[] = { /* These constants should exist on any langinfo implementation */ LANGINFO(DAY_1), LANGINFO(DAY_2), LANGINFO(DAY_3), LANGINFO(DAY_4), LANGINFO(DAY_5), LANGINFO(DAY_6), LANGINFO(DAY_7), LANGINFO(ABDAY_1), LANGINFO(ABDAY_2), LANGINFO(ABDAY_3), LANGINFO(ABDAY_4), LANGINFO(ABDAY_5), LANGINFO(ABDAY_6), LANGINFO(ABDAY_7), LANGINFO(MON_1), LANGINFO(MON_2), LANGINFO(MON_3), LANGINFO(MON_4), LANGINFO(MON_5), LANGINFO(MON_6), LANGINFO(MON_7), LANGINFO(MON_8), LANGINFO(MON_9), LANGINFO(MON_10), LANGINFO(MON_11), LANGINFO(MON_12), LANGINFO(ABMON_1), LANGINFO(ABMON_2), LANGINFO(ABMON_3), LANGINFO(ABMON_4), LANGINFO(ABMON_5), LANGINFO(ABMON_6), LANGINFO(ABMON_7), LANGINFO(ABMON_8), LANGINFO(ABMON_9), LANGINFO(ABMON_10), LANGINFO(ABMON_11), LANGINFO(ABMON_12), #ifdef RADIXCHAR /* The following are not available with glibc 2.0 */ LANGINFO(RADIXCHAR), LANGINFO(THOUSEP), /* YESSTR and NOSTR are deprecated in glibc, since they are a special case of message translation, which should be rather done using gettext. So we don't expose it to Python in the first place. LANGINFO(YESSTR), LANGINFO(NOSTR), */ LANGINFO(CRNCYSTR), #endif LANGINFO(D_T_FMT), LANGINFO(D_FMT), LANGINFO(T_FMT), LANGINFO(AM_STR), LANGINFO(PM_STR), /* The following constants are available only with XPG4, but... AIX 3.2. only has CODESET. OpenBSD doesn't have CODESET but has T_FMT_AMPM, and doesn't have a few of the others. Solution: ifdef-test them all. */ #ifdef CODESET LANGINFO(CODESET), #endif #ifdef T_FMT_AMPM LANGINFO(T_FMT_AMPM), #endif #ifdef ERA LANGINFO(ERA), #endif #ifdef ERA_D_FMT LANGINFO(ERA_D_FMT), #endif #ifdef ERA_D_T_FMT LANGINFO(ERA_D_T_FMT), #endif #ifdef ERA_T_FMT LANGINFO(ERA_T_FMT), #endif #ifdef ALT_DIGITS LANGINFO(ALT_DIGITS), #endif #ifdef YESEXPR LANGINFO(YESEXPR), #endif #ifdef NOEXPR LANGINFO(NOEXPR), #endif #ifdef _DATE_FMT /* This is not available in all glibc versions that have CODESET. */ LANGINFO(_DATE_FMT), #endif {0, 0} }; PyDoc_STRVAR(nl_langinfo__doc__, "nl_langinfo(key) -> string\n" "Return the value for the locale information associated with key."); static PyObject* PyLocale_nl_langinfo(PyObject* self, PyObject* args) { int item, i; if (!PyArg_ParseTuple(args, "i:nl_langinfo", &item)) return NULL; /* Check whether this is a supported constant. GNU libc sometimes returns numeric values in the char* return value, which would crash PyString_FromString. */ for (i = 0; langinfo_constants[i].name; i++) if (langinfo_constants[i].value == item) { /* Check NULL as a workaround for GNU libc's returning NULL instead of an empty string for nl_langinfo(ERA). */ const char *result = nl_langinfo(item); return PyString_FromString(result != NULL ? result : ""); } PyErr_SetString(PyExc_ValueError, "unsupported langinfo constant"); return NULL; } #endif /* HAVE_LANGINFO_H */ #ifdef HAVE_LIBINTL_H PyDoc_STRVAR(gettext__doc__, "gettext(msg) -> string\n" "Return translation of msg."); static PyObject* PyIntl_gettext(PyObject* self, PyObject *args) { char *in; if (!PyArg_ParseTuple(args, "z", &in)) return 0; return PyString_FromString(gettext(in)); } PyDoc_STRVAR(dgettext__doc__, "dgettext(domain, msg) -> string\n" "Return translation of msg in domain."); static PyObject* PyIntl_dgettext(PyObject* self, PyObject *args) { char *domain, *in; if (!PyArg_ParseTuple(args, "zz", &domain, &in)) return 0; return PyString_FromString(dgettext(domain, in)); } PyDoc_STRVAR(dcgettext__doc__, "dcgettext(domain, msg, category) -> string\n" "Return translation of msg in domain and category."); static PyObject* PyIntl_dcgettext(PyObject *self, PyObject *args) { char *domain, *msgid; int category; if (!PyArg_ParseTuple(args, "zzi", &domain, &msgid, &category)) return 0; return PyString_FromString(dcgettext(domain,msgid,category)); } PyDoc_STRVAR(textdomain__doc__, "textdomain(domain) -> string\n" "Set the C library's textdmain to domain, returning the new domain."); static PyObject* PyIntl_textdomain(PyObject* self, PyObject* args) { char *domain; if (!PyArg_ParseTuple(args, "z", &domain)) return 0; domain = textdomain(domain); if (!domain) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } return PyString_FromString(domain); } PyDoc_STRVAR(bindtextdomain__doc__, "bindtextdomain(domain, dir) -> string\n" "Bind the C library's domain to dir."); static PyObject* PyIntl_bindtextdomain(PyObject* self,PyObject*args) { char *domain,*dirname; if (!PyArg_ParseTuple(args, "zz", &domain, &dirname)) return 0; dirname = bindtextdomain(domain, dirname); if (!dirname) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } return PyString_FromString(dirname); } #ifdef HAVE_BIND_TEXTDOMAIN_CODESET PyDoc_STRVAR(bind_textdomain_codeset__doc__, "bind_textdomain_codeset(domain, codeset) -> string\n" "Bind the C library's domain to codeset."); static PyObject* PyIntl_bind_textdomain_codeset(PyObject* self,PyObject*args) { char *domain,*codeset; if (!PyArg_ParseTuple(args, "sz", &domain, &codeset)) return NULL; codeset = bind_textdomain_codeset(domain, codeset); if (codeset) return PyString_FromString(codeset); Py_RETURN_NONE; } #endif #endif static struct PyMethodDef PyLocale_Methods[] = { {"setlocale", (PyCFunction) PyLocale_setlocale, METH_VARARGS, setlocale__doc__}, {"localeconv", (PyCFunction) PyLocale_localeconv, METH_NOARGS, localeconv__doc__}, {"strcoll", (PyCFunction) PyLocale_strcoll, METH_VARARGS, strcoll__doc__}, {"strxfrm", (PyCFunction) PyLocale_strxfrm, METH_VARARGS, strxfrm__doc__}, #if defined(MS_WINDOWS) || defined(__APPLE__) {"_getdefaultlocale", (PyCFunction) PyLocale_getdefaultlocale, METH_NOARGS}, #endif #ifdef HAVE_LANGINFO_H {"nl_langinfo", (PyCFunction) PyLocale_nl_langinfo, METH_VARARGS, nl_langinfo__doc__}, #endif #ifdef HAVE_LIBINTL_H {"gettext",(PyCFunction)PyIntl_gettext,METH_VARARGS, gettext__doc__}, {"dgettext",(PyCFunction)PyIntl_dgettext,METH_VARARGS, dgettext__doc__}, {"dcgettext",(PyCFunction)PyIntl_dcgettext,METH_VARARGS, dcgettext__doc__}, {"textdomain",(PyCFunction)PyIntl_textdomain,METH_VARARGS, textdomain__doc__}, {"bindtextdomain",(PyCFunction)PyIntl_bindtextdomain,METH_VARARGS, bindtextdomain__doc__}, #ifdef HAVE_BIND_TEXTDOMAIN_CODESET {"bind_textdomain_codeset",(PyCFunction)PyIntl_bind_textdomain_codeset, METH_VARARGS, bind_textdomain_codeset__doc__}, #endif #endif {NULL, NULL} }; PyMODINIT_FUNC init_locale(void) { PyObject *m, *d, *x; #ifdef HAVE_LANGINFO_H int i; #endif m = Py_InitModule("_locale", PyLocale_Methods); if (m == NULL) return; d = PyModule_GetDict(m); x = PyInt_FromLong(LC_CTYPE); PyDict_SetItemString(d, "LC_CTYPE", x); Py_XDECREF(x); x = PyInt_FromLong(LC_TIME); PyDict_SetItemString(d, "LC_TIME", x); Py_XDECREF(x); x = PyInt_FromLong(LC_COLLATE); PyDict_SetItemString(d, "LC_COLLATE", x); Py_XDECREF(x); x = PyInt_FromLong(LC_MONETARY); PyDict_SetItemString(d, "LC_MONETARY", x); Py_XDECREF(x); #ifdef LC_MESSAGES x = PyInt_FromLong(LC_MESSAGES); PyDict_SetItemString(d, "LC_MESSAGES", x); Py_XDECREF(x); #endif /* LC_MESSAGES */ x = PyInt_FromLong(LC_NUMERIC); PyDict_SetItemString(d, "LC_NUMERIC", x); Py_XDECREF(x); x = PyInt_FromLong(LC_ALL); PyDict_SetItemString(d, "LC_ALL", x); Py_XDECREF(x); x = PyInt_FromLong(CHAR_MAX); PyDict_SetItemString(d, "CHAR_MAX", x); Py_XDECREF(x); Error = PyErr_NewException("locale.Error", NULL, NULL); PyDict_SetItemString(d, "Error", Error); x = PyString_FromString(locale__doc__); PyDict_SetItemString(d, "__doc__", x); Py_XDECREF(x); #ifdef HAVE_LANGINFO_H for (i = 0; langinfo_constants[i].name; i++) { PyModule_AddIntConstant(m, langinfo_constants[i].name, langinfo_constants[i].value); } #endif } /* Local variables: c-basic-offset: 4 indent-tabs-mode: nil End: */