From cde384411d1907d93369c144ec7b2f28da2628d5 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 7 Feb 2003 14:04:16 -0500 Subject: [PATCH] Several fixes/improvements: - Fixed CollapseFullPath to work on relative paths with base paths not in the current working directory. - INCLUDE command now supports relative paths (using above fix). - Added ABSOLUTE option to GET_FILENAME_COMPONENT command to unwind symlinks and relative paths. - Fixed libName_EXPORTS macro definition to be valid C identifier. - Added DEFINE_SYMBOL target propterty for customizing the export symbol. - Implemented LINK_FLAGS target propterty for libraries in VC6 and VC7. Several of these fixes were contributed by Gareth Jones. --- Source/cmGetFilenameComponentCommand.cxx | 6 +- Source/cmGetFilenameComponentCommand.h | 5 +- Source/cmLocalUnixMakefileGenerator.cxx | 13 +++- Source/cmLocalVisualStudio6Generator.cxx | 39 ++++++++-- Source/cmLocalVisualStudio6Generator.h | 2 +- Source/cmLocalVisualStudio7Generator.cxx | 41 +++++++++-- Source/cmLocalVisualStudio7Generator.h | 1 + Source/cmMakefile.cxx | 24 +++++- Source/cmSetSourceFilesPropertiesCommand.h | 10 ++- Source/cmSetTargetPropertiesCommand.h | 6 +- Source/cmSystemTools.cxx | 86 +++++++++++++++++----- Source/cmSystemTools.h | 15 +++- 12 files changed, 208 insertions(+), 40 deletions(-) diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx index 55f24a351..4cd609859 100644 --- a/Source/cmGetFilenameComponentCommand.cxx +++ b/Source/cmGetFilenameComponentCommand.cxx @@ -73,9 +73,13 @@ bool cmGetFilenameComponentCommand::InitialPass(std::vector const& { result = cmSystemTools::GetFilenameWithoutExtension(filename); } + else if (args[2] == "ABSOLUTE") + { + result = cmSystemTools::CollapseFullPath(filename.c_str()); + } else { - std::string err = "unknow component " + args[2]; + std::string err = "unknown component " + args[2]; this->SetError(err.c_str()); return false; } diff --git a/Source/cmGetFilenameComponentCommand.h b/Source/cmGetFilenameComponentCommand.h index c9d45bd50..73a5a9cfc 100644 --- a/Source/cmGetFilenameComponentCommand.h +++ b/Source/cmGetFilenameComponentCommand.h @@ -67,9 +67,10 @@ public: virtual const char* GetFullDocumentation() { return - "GET_FILENAME_COMPONENT(VarName FileName PATH|NAME|EXT|NAME_WE|PROGRAM [PROGRAM_ARGS ArgVarName] [CACHE])\n" + "GET_FILENAME_COMPONENT(VarName FileName PATH|ABSOLUTE|NAME|EXT|NAME_WE|PROGRAM [PROGRAM_ARGS ArgVarName] [CACHE])\n" "Set VarName to be the path (PATH), file name (NAME), file " - "extension (EXT) or file name without extension (NAME_WE) of FileName.\n" + "extension (EXT), file name without extension (NAME_WE) of FileName, " + "or the full absolute (ABSOLUTE) file name without symlinks. " "Note that the path is converted to Unix slashes format and has no " "trailing slashes. The longest file extension is always considered.\n" "Warning: as a utility command, the resulting value is not put in the " diff --git a/Source/cmLocalUnixMakefileGenerator.cxx b/Source/cmLocalUnixMakefileGenerator.cxx index 6acd51ec8..1079ce133 100644 --- a/Source/cmLocalUnixMakefileGenerator.cxx +++ b/Source/cmLocalUnixMakefileGenerator.cxx @@ -2477,7 +2477,18 @@ void cmLocalUnixMakefileGenerator::OutputSourceObjectBuildRules(std::ostream& fo std::string exportsDef = ""; if(shared) { - exportsDef = "-D"+target->first+"_EXPORTS "; + std::string export_symbol; + if (const char* custom_export_name = target->second.GetProperty("DEFINE_SYMBOL")) + { + export_symbol = custom_export_name; + } + else + { + std::string in = target->first + "_EXPORTS"; + export_symbol = cmSystemTools::MakeCindentifier(in.c_str()); + } + + exportsDef = "-D"+ export_symbol; } // Iterate over every source for this target. const std::vector& sources = target->second.GetSourceFiles(); diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index 5f0586dbb..bb251d358 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -82,20 +82,20 @@ void cmLocalVisualStudio6Generator::OutputDSPFile() switch(l->second.GetType()) { case cmTarget::STATIC_LIBRARY: - this->SetBuildType(STATIC_LIBRARY, l->first.c_str()); + this->SetBuildType(STATIC_LIBRARY, l->first.c_str(), l->second); break; case cmTarget::SHARED_LIBRARY: case cmTarget::MODULE_LIBRARY: - this->SetBuildType(DLL, l->first.c_str()); + this->SetBuildType(DLL, l->first.c_str(), l->second); break; case cmTarget::EXECUTABLE: - this->SetBuildType(EXECUTABLE,l->first.c_str()); + this->SetBuildType(EXECUTABLE,l->first.c_str(), l->second); break; case cmTarget::WIN32_EXECUTABLE: - this->SetBuildType(WIN32_EXECUTABLE,l->first.c_str()); + this->SetBuildType(WIN32_EXECUTABLE,l->first.c_str(), l->second); break; case cmTarget::UTILITY: - this->SetBuildType(UTILITY, l->first.c_str()); + this->SetBuildType(UTILITY, l->first.c_str(), l->second); break; case cmTarget::INSTALL_FILES: break; @@ -444,11 +444,25 @@ void cmLocalVisualStudio6Generator::WriteDSPEndGroup(std::ostream& fout) -void cmLocalVisualStudio6Generator::SetBuildType(BuildType b, const char *libName) +void cmLocalVisualStudio6Generator::SetBuildType(BuildType b, + const char* libName, + const cmTarget& target) { std::string root= m_Makefile->GetDefinition("CMAKE_ROOT"); const char *def= m_Makefile->GetDefinition( "MSPROJECT_TEMPLATE_DIRECTORY"); + std::string exportSymbol; + if (const char* custom_export_name = target.GetProperty("DEFINE_SYMBOL")) + { + exportSymbol = custom_export_name; + } + else + { + std::string in = libName; + in += "_EXPORTS"; + exportSymbol = cmSystemTools::MakeCindentifier(in.c_str()); + } + if( def) { root = def; @@ -510,6 +524,8 @@ void cmLocalVisualStudio6Generator::SetBuildType(BuildType b, const char *libNam { fin.getline(buffer, 2048); std::string line = buffer; + cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME_EXPORTS", + exportSymbol.c_str()); cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME",libName); if (reg.find(line)) { @@ -793,6 +809,17 @@ void cmLocalVisualStudio6Generator::WriteDSPHeader(std::ostream& fout, const cha libMultiLineOptions += extraLinkOptions; libMultiLineOptions += " \n"; } + + if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS")) + { + libOptions += " "; + libOptions += targetLinkFlags; + libOptions += " "; + libMultiLineOptions += "# ADD LINK32 "; + libMultiLineOptions += targetLinkFlags; + libMultiLineOptions += " \n"; + } + // are there any custom rules on the target itself // only if the target is a lib or exe diff --git a/Source/cmLocalVisualStudio6Generator.h b/Source/cmLocalVisualStudio6Generator.h index a9e1145cf..c3b20014c 100644 --- a/Source/cmLocalVisualStudio6Generator.h +++ b/Source/cmLocalVisualStudio6Generator.h @@ -56,7 +56,7 @@ public: /** * Specify the type of the build: static, dll, or executable. */ - void SetBuildType(BuildType,const char *name); + void SetBuildType(BuildType, const char* libName, const cmTarget&); /** * Return array of created DSP names in a STL vector. diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 69064ff47..ef287b95d 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -320,7 +320,18 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, if(target.GetType() == cmTarget::SHARED_LIBRARY || target.GetType() == cmTarget::MODULE_LIBRARY) { - fout << "," << libName << "_EXPORTS"; + std::string exportSymbol; + if (const char* custom_export_name = target.GetProperty("DEFINE_SYMBOL")) + { + exportSymbol = custom_export_name; + } + else + { + std::string id = libName; + id += "_EXPORTS"; + exportSymbol = cmSystemTools::MakeCindentifier(id.c_str()); + } + fout << "," << exportSymbol; } this->OutputDefineFlags(fout); fout << "\"\n"; @@ -368,6 +379,8 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, { debugPostfix = m_Makefile->GetDefinition("CMAKE_DEBUG_POSTFIX"); } + const char* targetLinkFlags = target.GetProperty("LINK_FLAGS"); + switch(target.GetType()) { case cmTarget::STATIC_LIBRARY: @@ -384,7 +397,13 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, case cmTarget::MODULE_LIBRARY: fout << "\t\t\tOutputLibraries(fout, configName, libName, target); fout << "\"\n"; @@ -429,7 +448,13 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, fout << "\t\t\tOutputLibraries(fout, configName, libName, target); fout << "\"\n"; @@ -980,11 +1005,17 @@ void cmLocalVisualStudio7Generator::WriteVCProjFooter(std::ostream& fout) } +std::string cmLocalVisualStudio7Generator::EscapeForXML(const char* s) +{ + std::string ret = s; + cmSystemTools::ReplaceString(ret, "\"", """); + return ret; +} + std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPath(const char* path) { std::string ret = cmSystemTools::ConvertToOutputPath(path); - cmSystemTools::ReplaceString(ret, "\"", """); - return ret; + return cmLocalVisualStudio7Generator::EscapeForXML(ret.c_str()); } std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPathSingle(const char* path) diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 8a74dcef9..b1ebe43f3 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -81,6 +81,7 @@ private: const char* configName, const char* libName, const cmTarget &tgt); + std::string EscapeForXML(const char* s); std::string ConvertToXMLOutputPath(const char* path); std::string ConvertToXMLOutputPathSingle(const char* path); void OutputDefineFlags(std::ostream& fout); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index a567f8382..7143f593f 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -231,12 +231,34 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff) // #include has been called). We DO NOT look at the parents of this // list-file, and for all other purposes, the name of this list-file // is "filename" and not "external". -bool cmMakefile::ReadListFile(const char* filename, const char* external) +bool cmMakefile::ReadListFile(const char* filename_in, const char* external_in) { // used to watch for blockers going out of scope // e.g. mismatched IF statement std::set originalBlockers; + + const char* external = 0; + std::string external_abs; + + const char* filename = filename_in; + std::string filename_abs; + + if (external_in) + { + external_abs = + cmSystemTools::CollapseFullPath(external_in, + m_cmCurrentDirectory.c_str()); + external = external_abs.c_str(); + if (filename_in) + { + filename_abs = + cmSystemTools::CollapseFullPath(filename_in, + m_cmCurrentDirectory.c_str()); + filename = filename_abs.c_str(); + } + } + // keep track of the current file being read if (filename) { diff --git a/Source/cmSetSourceFilesPropertiesCommand.h b/Source/cmSetSourceFilesPropertiesCommand.h index e935a34c5..1acbc64ff 100644 --- a/Source/cmSetSourceFilesPropertiesCommand.h +++ b/Source/cmSetSourceFilesPropertiesCommand.h @@ -55,7 +55,15 @@ public: return "SET_SOURCE_FILES_PROPERTIES(file1 file2 .. filen PROPERTIES prop1 value1 prop2 value2 ... prop2 valuen)" "Set properties on a file. The syntax for the command is to list all the files you want " - "to change, and then provide the values you want to set next. Common boolean properties ABSTRACT, WRAP_EXCLUDE, GENERATED and COMPILE_FLAGS. The first three are boolean properties (use a 1 or 0, TRUE or FALSE) while the COMPILE_FLAGS accepts any string. You can make up your own properties as well."; + "to change, and then provide the values you want to set next. You can make up your own properties as well. " + "The following are used by CMake. " + "The ABSTRACT flag (boolean) appears to have some effect on the VTK wrapper commands. " + "If WRAP_EXCLUDE (boolean) is true then the wrapping commands (FLTKWrapUI, QTWrapCC, QTWrapUI, VTKMakeInstantiator, VTKWrapJava, VTKWrapPython, and VTKWrapTcl) will ignore this file. " + "If GENERATED (boolean) is true then it is not an error if this source file does not exist when it is added to a target. Obviously, it must be created (presumably by a custom command) before the target is built. " + "If the HEADER_FILE_ONLY (boolean) property is true then dependency information is not created for that file (this is set automatically, based on the file's name's extension and is probably only used by Makefiles). " + "OBJECT_DEPENDS (string) adds dependencies to the object file. " + "COMPILE_FLAGS (string) is passed to the compiler as additional command line arguments when the source file is compiled. "; + } cmTypeMacro(cmSetSourceFilesPropertiesCommand, cmCommand); diff --git a/Source/cmSetTargetPropertiesCommand.h b/Source/cmSetTargetPropertiesCommand.h index d436433b5..b1e5c4712 100644 --- a/Source/cmSetTargetPropertiesCommand.h +++ b/Source/cmSetTargetPropertiesCommand.h @@ -55,7 +55,11 @@ public: return "SET_TARGET_PROPERTIES(target1 target2 .. filen PROPERTIES prop1 value1 prop2 value2 ... prop2 valuen)" "Set properties on a target. The syntax for the command is to list all the files you want " - "to change, and then provide the values you want to set next. Properties that cmake knows about are PREFIX and POSTFIX for Unix systems and libraries. CMake also knows about LINK_FLAGS, which can be used to add extra flags to the link step of a target. You can use and prop value pair you want and extract it later with the GET_TARGET_PROPERTY command."; + "to change, and then provide the values you want to set next. Properties that cmake knows about are PREFIX and POSTFIX for Unix systems and libraries. CMake also knows about LINK_FLAGS, which can be used to add extra flags to the link step of a target." + "DEFINE_SYMBOL is a symbol that is defined when compiling C or C++ sources. " + "If not set here then it is set to target_EXPORTS by default " + "(with some substitutions if target is not a valid C identifier). " + "You can use and prop value pair you want and extract it later with the GET_TARGET_PROPERTY command."; } cmTypeMacro(cmSetTargetPropertiesCommand, cmCommand); diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 99c04b050..b5f3d4484 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1768,24 +1768,42 @@ void cmSystemTools::SplitProgramPath(const char* in_name, /** * Given a path to a file or directory, convert it to a full path. - * This collapses away relative paths. The full path is returned. + * This collapses away relative paths relative to the cwd argument + * (which defaults to the current working directory). The full path + * is returned. */ -std::string cmSystemTools::CollapseFullPath(const char* in_name) +std::string cmSystemTools::CollapseFullPath(const char* in_relative) +{ + return cmSystemTools::CollapseFullPath(in_relative, 0); +} + +std::string cmSystemTools::CollapseFullPath(const char* in_relative, + const char* in_base) { std::string dir, file; - cmSystemTools::SplitProgramPath(in_name, dir, file); + cmSystemTools::SplitProgramPath(in_relative, dir, file); + + // Save original working directory. + std::string orig = cmSystemTools::GetCurrentWorkingDirectory(); + + // Change to base of relative path. + if(in_base) + { + Chdir(in_base); + } + #ifdef _WIN32 - // Ultra-hack warning: - // This changes to the target directory, saves the working directory, - // and then changes back to the original working directory. - std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); - if(dir != "") { Chdir(dir.c_str()); } + // Follow relative path. + if(dir != "") + { + Chdir(dir.c_str()); + } + + // Get the resulting directory. std::string newDir = cmSystemTools::GetCurrentWorkingDirectory(); - Chdir(cwd.c_str()); - + + // Add the file back on to the directory. cmSystemTools::ConvertToUnixSlashes(newDir); - std::string newPath = newDir+"/"+file; - return newPath; #else # ifdef MAXPATHLEN char resolved_name[MAXPATHLEN]; @@ -1796,21 +1814,31 @@ std::string cmSystemTools::CollapseFullPath(const char* in_name) char resolved_name[5024]; # endif # endif + + // Resolve relative path. + std::string newDir; if(dir != "") { realpath(dir.c_str(), resolved_name); - dir = resolved_name; + newDir = resolved_name; } else { - dir = cmSystemTools::GetCurrentWorkingDirectory(); + newDir = cmSystemTools::GetCurrentWorkingDirectory(); } - if(file == "") - { - return dir; - } - return dir + "/" + file; #endif + + // Restore original working directory. + Chdir(orig.c_str()); + + // Construct and return the full path. + std::string newPath = newDir; + if(file != "") + { + newPath += "/"; + newPath += file; + } + return newPath; } bool cmSystemTools::Split(const char* str, std::vector& lines) @@ -2330,6 +2358,26 @@ void cmSystemTools::SplitProgramFromArgs(const char* path, args = ""; } +std::string cmSystemTools::MakeCindentifier(const char* 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; +} + #if defined(_MSC_VER) && defined(_DEBUG) # include # include diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 3cd332112..e513733b1 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -28,6 +28,15 @@ class cmSystemTools { public: + /** + * 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 MakeCindentifier(const char* s); + /** * Make a new directory if it is not there. This function * can make a full path even if none of the directories existed @@ -256,8 +265,10 @@ public: static void SplitProgramPath(const char* in_name, std::string& dir, std::string& file); - static std::string CollapseFullPath(const char*); - + static std::string CollapseFullPath(const char* in_relative); + static std::string CollapseFullPath(const char* in_relative, + const char* in_base); + ///! return path of a full filename (no trailing slashes). static std::string GetFilenamePath(const std::string&);