From bea1a5de771832463299146b4f2e4317c37f30bc Mon Sep 17 00:00:00 2001 From: Alexander Neundorf Date: Wed, 11 Jul 2007 16:22:04 -0400 Subject: [PATCH] ENH: CMAKE__LINKER_PREFERENCE is now an integer priority, not a two-step priority (None or Prefered) Current order: ASM 0, C 10, Fortran 20, CXX 30, Java 40 This is the same order as automake choses: http://www.gnu.org/software/automake/manual/html_node/How-the-Linker-is-Chosen.html This change should be backward compatible: if there is a project using fortran and CXX, they had to set the LINKER_LANGUAGE explicitely, otherwise cmake complained (but still generated the project files). Explicitely setting the linker language still overrides automatic detection. If somebody has a custom language for cmake and the PREFERENCE starts with "P", its changed to 100, which gives it preference over all other languages (except the other custom languages which have also "Prefered"). "None" is converted to 0. Alex --- Modules/CMakeASMCompiler.cmake.in | 2 +- Modules/CMakeCCompiler.cmake.in | 2 +- Modules/CMakeCXXCompiler.cmake.in | 2 +- Modules/CMakeForceCompiler.cmake | 11 ++++ Modules/CMakeFortranCompiler.cmake.in | 2 +- Modules/CMakeJavaCompiler.cmake.in | 2 +- Modules/CMakeLists.txt | 2 +- Source/cmGlobalGenerator.cxx | 42 ++++++++---- Source/cmGlobalGenerator.h | 4 +- Source/cmTarget.cxx | 92 +++++++++++++-------------- 10 files changed, 95 insertions(+), 66 deletions(-) diff --git a/Modules/CMakeASMCompiler.cmake.in b/Modules/CMakeASMCompiler.cmake.in index f839a3e22..230805bf4 100644 --- a/Modules/CMakeASMCompiler.cmake.in +++ b/Modules/CMakeASMCompiler.cmake.in @@ -7,5 +7,5 @@ SET(CMAKE_ASM@ASM_DIALECT@_COMPILER_LOADED 1) SET(CMAKE_ASM@ASM_DIALECT@_COMPILER_ENV_VAR "@_CMAKE_ASM_COMPILER_ENV_VAR@") SET(CMAKE_ASM@ASM_DIALECT@_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) -SET(CMAKE_ASM@ASM_DIALECT@_LINKER_PREFERENCE None) +SET(CMAKE_ASM@ASM_DIALECT@_LINKER_PREFERENCE 0) diff --git a/Modules/CMakeCCompiler.cmake.in b/Modules/CMakeCCompiler.cmake.in index b746abaf8..6a7fef818 100644 --- a/Modules/CMakeCCompiler.cmake.in +++ b/Modules/CMakeCCompiler.cmake.in @@ -21,7 +21,7 @@ ENDIF(CMAKE_COMPILER_IS_MINGW) SET(CMAKE_C_COMPILER_ID_RUN 1) SET(CMAKE_C_SOURCE_FILE_EXTENSIONS c) SET(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) -SET(CMAKE_C_LINKER_PREFERENCE None) +SET(CMAKE_C_LINKER_PREFERENCE 10) # save the size of void* in case where cache is removed # and the this file is still around diff --git a/Modules/CMakeCXXCompiler.cmake.in b/Modules/CMakeCXXCompiler.cmake.in index f2c53d59c..b3a84dd1d 100644 --- a/Modules/CMakeCXXCompiler.cmake.in +++ b/Modules/CMakeCXXCompiler.cmake.in @@ -21,7 +21,7 @@ ENDIF(CMAKE_COMPILER_IS_MINGW) SET(CMAKE_CXX_COMPILER_ID_RUN 1) SET(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;H;o;O;obj;OBJ;def;DEF;rc;RC) SET(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm) -SET(CMAKE_CXX_LINKER_PREFERENCE Prefered) +SET(CMAKE_CXX_LINKER_PREFERENCE 30) # save the size of void* in case where cache is removed # and the this file is still around diff --git a/Modules/CMakeForceCompiler.cmake b/Modules/CMakeForceCompiler.cmake index d104ad9c0..751fd7850 100644 --- a/Modules/CMakeForceCompiler.cmake +++ b/Modules/CMakeForceCompiler.cmake @@ -38,6 +38,12 @@ MACRO(CMAKE_FORCE_C_COMPILER compiler id sizeof_void) SET(CMAKE_C_COMPILER_ID_RUN TRUE) SET(CMAKE_C_COMPILER_ID ${id}) SET(CMAKE_C_COMPILER_WORKS TRUE) + + # Set old compiler and platform id variables. + IF("${CMAKE_C_COMPILER_ID}" MATCHES "GNU") + SET(CMAKE_COMPILER_IS_GNUCC 1) + ENDIF("${CMAKE_C_COMPILER_ID}" MATCHES "GNU") + SET(CMAKE_SIZEOF_VOID_P ${sizeof_void} CACHE STRING "sizeof void") SET(HAVE_CMAKE_SIZEOF_VOID_P TRUE CACHE INTERNAL "have sizeof void") ENDMACRO(CMAKE_FORCE_C_COMPILER) @@ -47,5 +53,10 @@ MACRO(CMAKE_FORCE_CXX_COMPILER compiler id) SET(CMAKE_CXX_COMPILER_ID_RUN TRUE) SET(CMAKE_CXX_COMPILER_ID ${id}) SET(CMAKE_CXX_COMPILER_WORKS TRUE) + + IF("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + SET(CMAKE_COMPILER_IS_GNUCXX 1) + ENDIF("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + ENDMACRO(CMAKE_FORCE_CXX_COMPILER) diff --git a/Modules/CMakeFortranCompiler.cmake.in b/Modules/CMakeFortranCompiler.cmake.in index a4f3941ba..67a0c64a1 100644 --- a/Modules/CMakeFortranCompiler.cmake.in +++ b/Modules/CMakeFortranCompiler.cmake.in @@ -21,7 +21,7 @@ ENDIF(CMAKE_COMPILER_IS_MINGW) SET(CMAKE_Fortran_COMPILER_ID_RUN 1) SET(CMAKE_Fortran_SOURCE_FILE_EXTENSIONS f;F;f77;F77;f90;F90;for;f95;F95) SET(CMAKE_Fortran_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) -SET(CMAKE_Fortran_LINKER_PREFERENCE Prefered) +SET(CMAKE_Fortran_LINKER_PREFERENCE 20) IF(UNIX) SET(CMAKE_Fortran_OUTPUT_EXTENSION .o) ELSE(UNIX) diff --git a/Modules/CMakeJavaCompiler.cmake.in b/Modules/CMakeJavaCompiler.cmake.in index c9eeb14c8..83c1ee44a 100644 --- a/Modules/CMakeJavaCompiler.cmake.in +++ b/Modules/CMakeJavaCompiler.cmake.in @@ -5,7 +5,7 @@ SET(CMAKE_Java_ARCHIVE "@CMAKE_Java_ARCHIVE@") SET(CMAKE_Java_COMPILER_LOADED 1) SET(CMAKE_Java_SOURCE_FILE_EXTENSIONS java) -SET(CMAKE_Java_LINKER_PREFERENCE Prefered) +SET(CMAKE_Java_LINKER_PREFERENCE 40) SET(CMAKE_Java_OUTPUT_EXTENSION .class) SET(CMAKE_STATIC_LIBRARY_PREFIX_Java "") SET(CMAKE_STATIC_LIBRARY_SUFFIX_Java ".jar") diff --git a/Modules/CMakeLists.txt b/Modules/CMakeLists.txt index c575043b5..c3b5903e9 100644 --- a/Modules/CMakeLists.txt +++ b/Modules/CMakeLists.txt @@ -1,5 +1,5 @@ # just install the modules -# new file added, force rerunning cmake # +# new file added, force rerunning cmake SUBDIRS(Platform) INSTALL_FILES(${CMAKE_DATA_DIR}/Modules .*\\.cmake$) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index cea5b2b04..31adcf158 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -570,12 +570,35 @@ void cmGlobalGenerator::SetLanguageEnabledMaps(const char* l, cmMakefile* mf) std::string linkerPrefVar = std::string("CMAKE_") + std::string(l) + std::string("_LINKER_PREFERENCE"); const char* linkerPref = mf->GetDefinition(linkerPrefVar.c_str()); - if(!linkerPref) + int preference = 0; + if(linkerPref) { - linkerPref = "None"; + if (sscanf(linkerPref, "%d", &preference)!=1) + { + // backward compatibility: before 2.6 LINKER_PREFERENCE + // was either "None" or "Prefered", and only the first character was + // tested. So if there is a custom language out there and it is + // "Prefered", set its preference high + if (linkerPref[0]=='P') + { + preference = 100; + } + else + { + preference = 0; + } + } } - this->LanguageToLinkerPreference[l] = linkerPref; + 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"); @@ -752,10 +775,6 @@ void cmGlobalGenerator::Configure() } notFoundVars += "\n"; } - cmSystemTools::Error("This project requires some variables to be set,\n" - "and cmake can not find them.\n" - "Please set the following variables:\n", - notFoundVars.c_str()); } // at this point this->LocalGenerators has been filled, // so create the map from project name to vector of local generators @@ -1120,13 +1139,14 @@ void cmGlobalGenerator::GetEnabledLanguages(std::vector& lang) } } -const char* cmGlobalGenerator::GetLinkerPreference(const char* lang) +int cmGlobalGenerator::GetLinkerPreference(const char* lang) { - if(this->LanguageToLinkerPreference.count(lang)) + std::map::const_iterator it = this->LanguageToLinkerPreference.find(lang); + if (it != this->LanguageToLinkerPreference.end()) { - return this->LanguageToLinkerPreference[lang].c_str(); + return it->second; } - return "None"; + return 0; } void cmGlobalGenerator::FillProjectMap() diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 959945c98..ccf00d7f5 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -153,7 +153,7 @@ public: ///! is an extension to be ignored bool IgnoreFile(const char* ext); ///! What is the preference for linkers and this language (None or Prefered) - const char* GetLinkerPreference(const char* lang); + int GetLinkerPreference(const char* lang); ///! What is the object file extension for a given source file? const char* GetLanguageOutputExtension(cmSourceFile const&); @@ -257,7 +257,7 @@ private: std::map OutputExtensions; std::map LanguageToOutputExtension; std::map ExtensionToLanguage; - std::map LanguageToLinkerPreference; + std::map LanguageToLinkerPreference; // this is used to improve performance std::map TotalTargets; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 70d00352f..40132a5ef 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -1477,59 +1477,57 @@ const char* cmTarget::GetLinkerLanguage(cmGlobalGenerator* gg) const_cast(this)->SetProperty("LINKER_LANGUAGE", "CXX"); } const char* linkerLang = this->GetProperty("LINKER_LANGUAGE"); - if(linkerLang) + if (linkerLang==0) { - return linkerLang; - } - std::set languages; - for(std::vector::const_iterator i - = this->SourceFiles.begin(); - i != this->SourceFiles.end(); ++i) - { - if(const char* lang = (*i)->GetLanguage()) + // if the property has not yet been set, collect all languages in the + // target and then find the language with the highest preference value + std::set languages; + for(std::vector::const_iterator + i = this->SourceFiles.begin(); i != this->SourceFiles.end(); ++i) { - languages.insert(lang); - } - } - if(languages.size() == 0) - { - return 0; - } - if(languages.size() == 1) - { - const_cast(this)->SetProperty("LINKER_LANGUAGE", - languages.begin()->c_str()); - return this->GetProperty("LINKER_LANGUAGE"); - } - const char* prefLang = 0; - for(std::set::const_iterator s = languages.begin(); - s != languages.end(); ++s) - { - const char* lpref = gg->GetLinkerPreference(s->c_str()); - if(lpref[0] == 'P') - { - if(prefLang && !(*s == prefLang)) + if(const char* lang = (*i)->GetLanguage()) { - std::string m = "Error Target: "; - m += this->Name + " Contains more than one Prefered language: "; - m += *s; - m += " and "; - m += prefLang; - m += "\nYou must set the LINKER_LANGUAGE property for this target."; - cmSystemTools::Error(m.c_str()); - } - else - { - prefLang = s->c_str(); + languages.insert(lang); } } + + std::string linkerLangList; // only used for the error message + int maxLinkerPref = 0; + bool multiplePreferedLanguages = false; + for(std::set::const_iterator sit = languages.begin(); + sit != languages.end(); ++sit) + { + int linkerPref = gg->GetLinkerPreference(sit->c_str()); + if ((linkerPref > maxLinkerPref) || (linkerLang==0)) + { + maxLinkerPref = linkerPref; + linkerLang = sit->c_str(); + linkerLangList = *sit; + multiplePreferedLanguages = false; + } + else if (linkerPref == maxLinkerPref) + { + linkerLangList += "; "; + linkerLangList += *sit; + multiplePreferedLanguages = true; + } + } + + if (linkerLang!=0) + { + const_cast(this)->SetProperty("LINKER_LANGUAGE", linkerLang); + } + if (multiplePreferedLanguages) + { + cmOStringStream err; + err << "Error: Target " << this->Name << " contains multiple languages " + << "with the highest linker preference (" << maxLinkerPref << "): " + << linkerLangList << "\n" + << "You must set the LINKER_LANGUAGE property for this target."; + cmSystemTools::Error(err.str().c_str()); + } } - if(!prefLang) - { - prefLang = languages.begin()->c_str(); - } - const_cast(this)->SetProperty("LINKER_LANGUAGE", prefLang); - return this->GetProperty("LINKER_LANGUAGE"); + return linkerLang; } //----------------------------------------------------------------------------