/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile$ Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) 2002 Insight Consortium. All rights reserved. See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "cmNMakeMakefileGenerator.h" #include "cmMakefile.h" #include "cmStandardIncludes.h" #include "cmSystemTools.h" #include "cmSourceFile.h" #include "cmMakeDepend.h" #include "cmCacheManager.h" #include "cmGeneratedFileStream.h" #include "windows.h" cmNMakeMakefileGenerator::cmNMakeMakefileGenerator() { this->SetLibraryPathOption("@CMAKE_C_LIBPATH_FLAG@"); // Use @ here this->SetObjectFileExtension("$(CMAKE_OBJECT_FILE_SUFFIX)"); this->SetExecutableExtension("$(CMAKE_EXECUTABLE_SUFFIX)"); this->SetLibraryPrefix(""); this->SetStaticLibraryExtension("$(CMAKE_STATICLIB_SUFFIX)"); this->SetSharedLibraryExtension("$(CMAKE_SHLIB_SUFFIX)"); } cmNMakeMakefileGenerator::~cmNMakeMakefileGenerator() { } // convert to windows short paths if there are spaces // in path std::string cmNMakeMakefileGenerator::ShortPath(const char* path) { std::string ret = path; // if there are no spaces in path, then just // call ConvertToOutputPath if(ret.find(' ') == std::string::npos) { return this->ConvertToOutputPath(path); } // if there are spaces then call GetShortPathName to get rid of them if(!cmSystemTools::GetShortPath(path, ret)) { // if GetShortPathName failed for some reason use // ConvertToOutputPath instead which will at least escape the spaces ret = this->ConvertToOutputPath(path); return ret; } ret = this->ConvertToOutputPath(ret.c_str()); return ret; } // convert a command to a short path if it has spaces // this separates the arguments from the command and puts // them back together std::string cmNMakeMakefileGenerator::ShortPathCommand(const char* command) { if (!command) { return ""; } if(!strchr(command, ' ')) { return command; } cmRegularExpression reg("^\"([^\"]*)\"(.*)"); if(reg.find(command)) { std::string c = reg.match(1); cmRegularExpression removeIntDir("(.*)(/|\\\\)\\$\\(IntDir\\)(.*)"); if(removeIntDir.find(c)) { c = removeIntDir.match(1) + removeIntDir.match(3); } std::string unixPath = c; // since the command may already be a windows path, convert it // to unix so we can use SplitProgramPath on it. cmSystemTools::ConvertToUnixSlashes(unixPath); std::string path, file; cmSystemTools::SplitProgramPath(unixPath.c_str(), path, file); // do a short path on the directory, because ShortPath will // not work for files that do not exist path = this->ShortPath(path.c_str()); // now put the two back together path += "\\"; path += file; std::string ret = path; std::string args = reg.match(2); ret += args; return ret; } return command; } void cmNMakeMakefileGenerator::EnableLanguage(const char*) { // now load the settings if(!m_Makefile->GetDefinition("CMAKE_ROOT")) { cmSystemTools::Error( "CMAKE_ROOT has not been defined, bad GUI or driver program"); return; } if(!this->GetLanguageEnabled("CXX")) { std::string fpath = m_Makefile->GetDefinition("CMAKE_ROOT"); fpath += "/Templates/CMakeNMakeWindowsSystemConfig.cmake"; m_Makefile->ReadListFile(NULL,fpath.c_str()); this->SetLanguageEnabled("CXX"); } } void cmNMakeMakefileGenerator::OutputMakeVariables(std::ostream& fout) { fout << "# NMake Makefile generated by cmake\n"; const char* variables = "# general variables used in the makefile\n" "\n" "# Path to cmake\n" "MAKESILENT = /nologo\n" "CMAKE_STANDARD_WINDOWS_LIBRARIES = @CMAKE_STANDARD_WINDOWS_LIBRARIES@\n" "CMAKE_C_FLAGS = @CMAKE_C_FLAGS@ @BUILD_FLAGS@ -DWIN32\n" "CMAKE_C_LINK_EXECUTABLE_FLAG = @CMAKE_C_LINK_EXECUTABLE_FLAG@\n" "CMAKE_CXX_FLAGS = @CMAKE_CXX_FLAGS@ -DWIN32 @BUILD_FLAGS@\n" "CMAKE_LINKER_FLAGS = @CMAKE_LINKER_FLAGS@ @LINKER_BUILD_FLAGS@\n" "CMAKE_LINKER_SHARED_LIBRARY_FLAG = @CMAKE_LINKER_SHARED_LIBRARY_FLAG@\n" "CMAKE_LIBRARY_MANAGER_FLAGS = @CMAKE_LIBRARY_MANAGER_FLAGS@\n" "CMAKE_OBJECT_FILE_SUFFIX = @CMAKE_OBJECT_FILE_SUFFIX@\n" "CMAKE_EXECUTABLE_SUFFIX = @CMAKE_EXECUTABLE_SUFFIX@\n" "CMAKE_STATICLIB_SUFFIX = @CMAKE_STATICLIB_SUFFIX@\n" "CMAKE_SHLIB_SUFFIX = @CMAKE_SHLIB_SUFFIX@\n" "!IF \"$(OS)\" == \"Windows_NT\"\n" "NULL=\n" "!ELSE \n" "NULL=nul\n" "!ENDIF \n"; std::string buildType = "CMAKE_CXX_FLAGS_"; buildType += m_Makefile->GetDefinition("CMAKE_BUILD_TYPE"); buildType = cmSystemTools::UpperCase(buildType); m_Makefile->AddDefinition("BUILD_FLAGS", m_Makefile->GetDefinition( buildType.c_str())); buildType = "CMAKE_LINKER_FLAGS_"; buildType += m_Makefile->GetDefinition("CMAKE_BUILD_TYPE"); buildType = cmSystemTools::UpperCase(buildType); m_Makefile->AddDefinition("LINKER_BUILD_FLAGS", m_Makefile->GetDefinition( buildType.c_str())); std::string replaceVars = variables; m_Makefile->ExpandVariablesInString(replaceVars); fout << replaceVars.c_str(); std::string ccompiler = m_Makefile->GetDefinition("CMAKE_C_COMPILER"); fout << "CMAKE_C_COMPILER = " << this->ShortPath(ccompiler.c_str()) << "\n"; std::string cxxcompiler = m_Makefile->GetDefinition("CMAKE_CXX_COMPILER"); fout << "CMAKE_CXX_COMPILER = " << this->ShortPath(cxxcompiler.c_str()) << "\n"; std::string linker = m_Makefile->GetDefinition("CMAKE_LINKER"); fout << "CMAKE_LINKER = " << this->ShortPath(linker.c_str()) << "\n"; std::string lib_manager = m_Makefile->GetDefinition("CMAKE_LIBRARY_MANAGER"); fout << "CMAKE_LIBRARY_MANAGER = " << this->ShortPath(lib_manager.c_str()) << "\n"; std::string cmakecommand = m_Makefile->GetDefinition("CMAKE_COMMAND"); fout << "CMAKE_COMMAND = " << this->ShortPath(cmakecommand.c_str()) << "\n"; fout << "RM = " << this->ShortPath(cmakecommand.c_str()) << " -E remove -f\n"; if(m_Makefile->GetDefinition("CMAKE_EDIT_COMMAND")) { fout << "CMAKE_EDIT_COMMAND = " << this->ShortPath(m_Makefile->GetDefinition("CMAKE_EDIT_COMMAND")) << "\n"; } fout << "CMAKE_CURRENT_SOURCE = " << this->ShortPath(m_Makefile->GetStartDirectory() ) << "\n"; fout << "CMAKE_CURRENT_BINARY = " << this->ShortPath(m_Makefile->GetStartOutputDirectory()) << "\n"; fout << "CMAKE_SOURCE_DIR = " << this->ShortPath(m_Makefile->GetHomeDirectory()) << "\n"; fout << "CMAKE_BINARY_DIR = " << this->ShortPath(m_Makefile->GetHomeOutputDirectory() ) << "\n"; // Output Include paths fout << "INCLUDE_FLAGS = "; std::vector& includes = m_Makefile->GetIncludeDirectories(); std::vector::iterator i; fout << "-I" << this->ConvertToOutputPath(m_Makefile->GetStartDirectory()) << " "; for(i = includes.begin(); i != includes.end(); ++i) { std::string include = *i; // Don't output a -I for the standard include path "/usr/include". // This can cause problems with certain standard library // implementations because the wrong headers may be found first. fout << "-I" << this->ConvertToOutputPath(i->c_str()).c_str() << " "; } fout << m_Makefile->GetDefineFlags(); fout << "\n\n"; } void cmNMakeMakefileGenerator::BuildInSubDirectory(std::ostream& fout, const char* directory, const char* target1, const char* target2, bool silent) { if(target1) { std::string dir = this->ConvertToOutputPath(directory); fout << "\tif not exist \"" << dir << "\\$(NULL)\"" << " " << "$(MAKE) $(MAKESILENT) rebuild_cache\n"; if (!silent) { fout << "\techo " << directory << ": building " << target1 << "\n"; } fout << "\tcd " << dir << "\n" << "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) " << target1 << "\n"; } if(target2) { if (!silent) { fout << "\techo " << directory << ": building " << target2 << "\n"; } fout << "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) " << target2 << "\n"; } std::string currentDir = m_Makefile->GetCurrentOutputDirectory(); fout << "\tcd " << this->ConvertToOutputPath(currentDir.c_str()) << "\n\n"; } // This needs to be overriden because nmake requires commands to be quoted // if the are full paths to the executable???? void cmNMakeMakefileGenerator::OutputMakeRule(std::ostream& fout, const char* comment, const char* target, const char* depends, const char* command, const char* command2, const char* command3, const char* command4) { std::string short_command; if (command) { short_command = ShortPathCommand(command); command = short_command.c_str(); } std::string short_command2; if (command2) { short_command2 = ShortPathCommand(command2); command2 = short_command2.c_str(); } std::string short_command3; if (command3) { short_command3 = ShortPathCommand(command3); command3 = short_command3.c_str(); } std::string short_command4; if (command4) { short_command4 = ShortPathCommand(command4); command4 = short_command4.c_str(); } cmUnixMakefileGenerator::OutputMakeRule(fout, comment, target, depends, command, command2, command3, command4); return; } void cmNMakeMakefileGenerator:: OutputBuildObjectFromSource(std::ostream& fout, const char* shortName, const cmSourceFile& source, const char* extraCompileFlags, bool shared) { // Header files shouldn't have build rules. if(source.GetPropertyAsBool("HEADER_FILE_ONLY")) { return; } std::string comment = "Build "; std::string objectFile = std::string(shortName) + this->GetOutputExtension(source.GetSourceExtension().c_str()); comment += objectFile + " From "; comment += source.GetFullPath(); std::string compileCommand; std::string ext = source.GetSourceExtension(); if(ext == "c" ) { compileCommand = "$(CMAKE_C_COMPILER) $(CMAKE_C_FLAGS) "; compileCommand += extraCompileFlags; if(shared) { compileCommand += "$(CMAKE_SHLIB_CFLAGS) "; } compileCommand += "$(INCLUDE_FLAGS) -c "; compileCommand += this->ConvertToOutputPath(source.GetFullPath().c_str()); // Need to get the definition here because this value might have // trailing space (since it is directly prepended to the filename) std::string output_object_file_flag = m_Makefile->GetDefinition("CMAKE_C_OUTPUT_OBJECT_FILE_FLAG"); m_Makefile->ExpandVariablesInString(output_object_file_flag); compileCommand += " " + output_object_file_flag; compileCommand += objectFile; } else if (ext == "rc") { compileCommand = "$(RC) $(INCLUDE_FLAGS) /fo\""; compileCommand += objectFile; compileCommand += "\" "; compileCommand += this->ConvertToOutputPath(source.GetFullPath().c_str()); } else if (ext == "def") { // no rule to output for this one return; } // assume c++ if not c rc or def else { compileCommand = "$(CMAKE_CXX_COMPILER) $(CMAKE_CXX_FLAGS) "; compileCommand += extraCompileFlags; if(shared) { compileCommand += "$(CMAKE_SHLIB_CFLAGS) "; } compileCommand += "$(INCLUDE_FLAGS) -c "; compileCommand += this->ConvertToOutputPath(source.GetFullPath().c_str()); // Need to get the definition here because this value might have // trailing space (since it is directly prepended to the filename) std::string output_object_file_flag = m_Makefile->GetDefinition("CMAKE_C_OUTPUT_OBJECT_FILE_FLAG"); m_Makefile->ExpandVariablesInString(output_object_file_flag); compileCommand += " " + output_object_file_flag; compileCommand += objectFile; } this->OutputMakeRule(fout, comment.c_str(), objectFile.c_str(), this->ConvertToOutputPath( source.GetFullPath().c_str()).c_str(), compileCommand.c_str()); } void cmNMakeMakefileGenerator::OutputSharedLibraryRule(std::ostream& fout, const char* name, const cmTarget &t) { std::string target = m_LibraryOutputPath + name + m_SharedLibraryExtension; std::string depend = "$("; depend += this->CreateMakeVariable(name, "_SRC_OBJS"); depend += ") $(" + this->CreateMakeVariable(name, "_DEPEND_LIBS") + ")"; // Need to get the definition here because this value might have // trailing space (since it is directly prepended to the filename) std::string linker_output_file_flag = m_Makefile->GetDefinition("CMAKE_LINKER_OUTPUT_FILE_FLAG"); m_Makefile->ExpandVariablesInString(linker_output_file_flag); std::string command = "$(CMAKE_LINKER) $(CMAKE_LINKER_SHARED_LIBRARY_FLAG)"; bool hide_param = m_Makefile->IsOn("CMAKE_LINKER_HIDE_PARAMETERS"); if (hide_param) { command += " @<<\n\t"; } command += " $(CMAKE_LINKER_FLAGS) " + linker_output_file_flag; std::string dllpath = m_LibraryOutputPath + std::string(name) + m_SharedLibraryExtension; command += this->ConvertToOutputPath(dllpath.c_str()); command += " $(" + this->CreateMakeVariable(name, "_SRC_OBJS") + ") "; cmStringStream linklibs; this->OutputLinkLibraries(linklibs, name, t); command += linklibs.str(); const std::vector& sources = t.GetSourceFiles(); for(std::vector::const_iterator i = sources.begin(); i != sources.end(); ++i) { if((*i)->GetSourceExtension() == "def") { command += "/DEF:"; command += (*i)->GetFullPath(); } } command += "\n"; if (hide_param) { command += "<<\n"; } std::string customCommands = this->CreateTargetRules(t, name); const char* cc = 0; if(customCommands.size() > 0) { cc = customCommands.c_str(); } this->OutputMakeRule(fout, "rules for a shared library", target.c_str(), depend.c_str(), command.c_str(), cc); } void cmNMakeMakefileGenerator::OutputModuleLibraryRule(std::ostream& fout, const char* name, const cmTarget &target) { this->OutputSharedLibraryRule(fout, name, target); } void cmNMakeMakefileGenerator::OutputStaticLibraryRule(std::ostream& fout, const char* name, const cmTarget &t) { std::string target = m_LibraryOutputPath + std::string(name) + m_StaticLibraryExtension; std::string depend = "$("; depend += this->CreateMakeVariable(name, "_SRC_OBJS") + ") "; // Need to get the definition here because this value might have // trailing space (since it is directly prepended to the filename) std::string library_manager_output_file_flag = m_Makefile->GetDefinition("CMAKE_LIBRARY_MANAGER_OUTPUT_FILE_FLAG"); m_Makefile->ExpandVariablesInString(library_manager_output_file_flag); std::string command = "$(CMAKE_LIBRARY_MANAGER) $(CMAKE_LIBRARY_MANAGER_FLAGS) @<<\n\t " + library_manager_output_file_flag; std::string libpath = m_LibraryOutputPath + std::string(name) + m_StaticLibraryExtension; command += this->ConvertToOutputPath(libpath.c_str()); command += " $("; command += this->CreateMakeVariable(name, "_SRC_OBJS") + ")"; command += "\n<<\n"; std::string comment = "rule to build static library: "; comment += name; std::string customCommands = this->CreateTargetRules(t, name); const char* cc = 0; if(customCommands.size() > 0) { cc = customCommands.c_str(); } this->OutputMakeRule(fout, comment.c_str(), target.c_str(), depend.c_str(), command.c_str(), cc); } void cmNMakeMakefileGenerator::OutputExecutableRule(std::ostream& fout, const char* name, const cmTarget &t) { std::string target = m_ExecutableOutputPath + name; target += m_ExecutableExtension; std::string depend = "$("; depend += this->CreateMakeVariable(name, "_SRC_OBJS") + ") $(" + this->CreateMakeVariable(name, "_DEPEND_LIBS") + ")"; std::string command; if(t.HasCxx()) { command = "$(CMAKE_CXX_COMPILER) $(CMAKE_CXX_FLAGS) "; } else { command = "${CMAKE_C_COMPILER} $(CMAKE_C_FLAGS) "; } bool hide_param = m_Makefile->IsOn("CMAKE_LINKER_HIDE_PARAMETERS"); if (hide_param) { command += " @<<\n\t"; } command += "$(" + this->CreateMakeVariable(name, "_SRC_OBJS") + ") "; std::string path = m_ExecutableOutputPath + name + m_ExecutableExtension; // Need to get the definition here because this value might have // trailing space (since it is directly prepended to the filename) std::string output_executable_file_flag = m_Makefile->GetDefinition("CMAKE_C_OUTPUT_EXECUTABLE_FILE_FLAG"); m_Makefile->ExpandVariablesInString(output_executable_file_flag); command += " " + output_executable_file_flag + this->ConvertToOutputPath(path.c_str()); command += " $(CMAKE_C_LINK_EXECUTABLE_FLAG) $(CMAKE_LINKER_FLAGS) "; if(t.GetType() == cmTarget::WIN32_EXECUTABLE) { command += " /subsystem:windows "; } cmStringStream linklibs; this->OutputLinkLibraries(linklibs, 0, t); command += linklibs.str(); std::string comment = "rule to build executable: "; comment += name; std::string customCommands = this->CreateTargetRules(t, name); const char* cc = 0; if(customCommands.size() > 0) { cc = customCommands.c_str(); } if (hide_param) { command += "\n"; command += "<<\n"; } this->OutputMakeRule(fout, comment.c_str(), target.c_str(), depend.c_str(), command.c_str(), cc); } void cmNMakeMakefileGenerator::OutputLinkLibraries(std::ostream& fout, const char* targetLibrary, const cmTarget &tgt) { // Try to emit each search path once std::set emitted; // Embed runtime search paths if possible and if required. // collect all the flags needed for linking libraries // Do not try if there is no library path option (it is set to -L or // -LIBPATH for some linker, but some others do not even support link // search path). std::string linkLibs; // Expand content because this value might have // trailing space (since it is directly prepended to the filename) std::string lib_path_opt = m_LibraryPathOption; m_Makefile->ExpandVariablesInString(lib_path_opt); if (lib_path_opt.size()) { const std::vector& libdirs = tgt.GetLinkDirectories(); for(std::vector::const_iterator libDir = libdirs.begin(); libDir != libdirs.end(); ++libDir) { std::string libpath = ShortPath(libDir->c_str()); if(emitted.insert(libpath).second) { linkLibs += lib_path_opt; this->ConvertToOutputPath(libpath.c_str()); linkLibs += libpath; linkLibs += " "; } } } std::string librariesLinked; const cmTarget::LinkLibraries& libs = tgt.GetLinkLibraries(); for(cmTarget::LinkLibraries::const_iterator lib = libs.begin(); lib != libs.end(); ++lib) { // Don't link the library against itself! if(targetLibrary && (lib->first == targetLibrary)) continue; // ** should fix this later, it should check to see if this is // a debug build and add the library // don't look at debug libraries // if (lib->second == cmTarget::DEBUG) continue; // skip zero size library entries, this may happen // if a variable expands to nothing. if (lib->first.size() == 0) continue; if(emitted.insert(lib->first).second) { std::string regexp = ".*\\"; regexp += m_Makefile->GetDefinition("CMAKE_STATICLIB_SUFFIX"); regexp += "$"; cmRegularExpression reg(regexp.c_str()); // if it ends in .lib, then it is a full path and should // be escaped, and does not need .lib added if(reg.find(lib->first)) { librariesLinked += ShortPath(lib->first.c_str()); librariesLinked += " "; } else { librariesLinked += m_LibraryLinkOption; librariesLinked += lib->first; librariesLinked += m_StaticLibraryExtension + " "; } } } linkLibs += librariesLinked; fout << linkLibs; fout << "$(CMAKE_STANDARD_WINDOWS_LIBRARIES) "; } std::string cmNMakeMakefileGenerator::GetOutputExtension(const char* s) { std::string sourceExtension = s; if(sourceExtension == "def") { return ""; } if(sourceExtension == "ico" || sourceExtension == "rc2") { return ""; } if(sourceExtension == "rc") { return ".res"; } return m_ObjectFileExtension; } void cmNMakeMakefileGenerator::OutputIncludeMakefile(std::ostream& fout, const char* file) { fout << "!include " << file << "\n"; } bool cmNMakeMakefileGenerator::SamePath(const char* path1, const char* path2) { // first check to see if they are the same anyway if (strcmp(path1, path2) == 0) { return true; } // next short path and lower case both of them for the compare return cmSystemTools::LowerCase(ShortPath(path1)) == cmSystemTools::LowerCase(ShortPath(path2)); } void cmNMakeMakefileGenerator::OutputBuildTargetInDir(std::ostream& fout, const char* path, const char* library, const char* fullpath, const char* libOutPath) { const char* makeTarget = library; std::string currentDir = this->ConvertToOutputPath(m_Makefile->GetCurrentOutputDirectory()); std::string wpath = this->ConvertToOutputPath(path); std::string wfullpath = this->ConvertToOutputPath(fullpath); if(libOutPath && strcmp( libOutPath, "" ) != 0) { makeTarget = wfullpath.c_str(); } fout << wfullpath << ":\n\tcd " << wpath << "\n" << "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) cmake.depends\n" << "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) cmake.check_depends\n" << "\t$(MAKE) -$(MAKEFLAGS) $(MAKESILENT) -f cmake.check_depends\n" << "\t$(MAKE) $(MAKESILENT) " << makeTarget << "\n\tcd " << currentDir << "\n"; } std::string cmNMakeMakefileGenerator::ConvertToOutputPath(const char* s) { return cmSystemTools::ConvertToOutputPath(s); } std::string cmNMakeMakefileGenerator::CreateMakeVariable(const char* s, const char* s2) { std::string ret= std::string(s) + std::string(s2); cmSystemTools::ReplaceString(ret, "-", "_"); return ret; } std::string cmNMakeMakefileGenerator::LowerCasePath(const char* path) { return cmSystemTools::LowerCase(path); }