| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file Copyright.txt or https://cmake.org/licensing for details. */ | |
| #include "cmExportLibraryDependenciesCommand.h" | |
| #include <map> | |
| #include <utility> | |
| #include <cm/memory> | |
| #include "cmsys/FStream.hxx" | |
| #include "cmExecutionStatus.h" | |
| #include "cmGeneratedFileStream.h" | |
| #include "cmGlobalGenerator.h" | |
| #include "cmLocalGenerator.h" | |
| #include "cmMakefile.h" | |
| #include "cmProperty.h" | |
| #include "cmStateTypes.h" | |
| #include "cmStringAlgorithms.h" | |
| #include "cmSystemTools.h" | |
| #include "cmTarget.h" | |
| #include "cmTargetLinkLibraryType.h" | |
| #include "cmake.h" | |
| class cmListFileBacktrace; | |
| static void FinalAction(cmMakefile& makefile, std::string const& filename, | |
| bool append) | |
| { | |
| // Use copy-if-different if not appending. | |
| std::unique_ptr<cmsys::ofstream> foutPtr; | |
| if (append) { | |
| const auto openmodeApp = std::ios::app; | |
| foutPtr = cm::make_unique<cmsys::ofstream>(filename.c_str(), openmodeApp); | |
| } else { | |
| std::unique_ptr<cmGeneratedFileStream> ap( | |
| new cmGeneratedFileStream(filename, true)); | |
| ap->SetCopyIfDifferent(true); | |
| foutPtr = std::move(ap); | |
| } | |
| std::ostream& fout = *foutPtr; | |
| if (!fout) { | |
| cmSystemTools::Error("Error Writing " + filename); | |
| cmSystemTools::ReportLastSystemError(""); | |
| return; | |
| } | |
| // Collect dependency information about all library targets built in | |
| // the project. | |
| cmake* cm = makefile.GetCMakeInstance(); | |
| cmGlobalGenerator* global = cm->GetGlobalGenerator(); | |
| const auto& 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 (const auto& local : locals) { | |
| for (auto const& tgt : local->GetTargets()) { | |
| // Get the current target. | |
| cmTarget const& target = tgt.second; | |
| // Skip non-library targets. | |
| if (target.GetType() < cmStateEnums::STATIC_LIBRARY || | |
| target.GetType() > cmStateEnums::MODULE_LIBRARY) { | |
| continue; | |
| } | |
| // Construct the dependency variable name. | |
| std::string targetEntry = cmStrCat(target.GetName(), "_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::LibraryID const& li : libs) { | |
| std::string ltVar = cmStrCat(li.first, "_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 (cmProp 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\n\n"; | |
| fout << "if(" << vertest << ")\n"; | |
| fout << " # Information for CMake 2.6 and above.\n"; | |
| for (auto const& i : libDepsNew) { | |
| if (!i.second.empty()) { | |
| fout << " set(\"" << i.first << "\" \"" << i.second << "\")\n"; | |
| } | |
| } | |
| fout << "else()\n"; | |
| fout << " # Information for CMake 2.4 and lower.\n"; | |
| for (auto const& i : libDepsOld) { | |
| if (!i.second.empty()) { | |
| fout << " set(\"" << i.first << "\" \"" << i.second << "\")\n"; | |
| } | |
| } | |
| for (auto const& i : libTypes) { | |
| if (i.second != "general") { | |
| fout << " set(\"" << i.first << "\" \"" << i.second << "\")\n"; | |
| } | |
| } | |
| fout << "endif()\n"; | |
| } | |
| bool cmExportLibraryDependenciesCommand(std::vector<std::string> const& args, | |
| cmExecutionStatus& status) | |
| { | |
| if (args.empty()) { | |
| status.SetError("called with incorrect number of arguments"); | |
| return false; | |
| } | |
| std::string const& filename = args[0]; | |
| bool const append = args.size() > 1 && args[1] == "APPEND"; | |
| status.GetMakefile().AddGeneratorAction( | |
| [filename, append](cmLocalGenerator& lg, const cmListFileBacktrace&) { | |
| FinalAction(*lg.GetMakefile(), filename, append); | |
| }); | |
| return true; | |
| } |