ENH: Create COMPILE_DEFINITIONS property for targets and source files. Create <config>_COMPILE_DEFINITIONS property as per-configuration version. Add Preprocess test to test the feature. Document limitations on Xcode and VS6 generators.
This commit is contained in:
parent
2c42f75522
commit
8262ccfd4e
|
@ -141,7 +141,7 @@ ENDIF(NOT CMAKE_C_CREATE_STATIC_LIBRARY)
|
|||
# compile a C file into an object file
|
||||
IF(NOT CMAKE_C_COMPILE_OBJECT)
|
||||
SET(CMAKE_C_COMPILE_OBJECT
|
||||
"<CMAKE_C_COMPILER> <FLAGS> -o <OBJECT> -c <SOURCE>")
|
||||
"<CMAKE_C_COMPILER> <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>")
|
||||
ENDIF(NOT CMAKE_C_COMPILE_OBJECT)
|
||||
|
||||
IF(NOT CMAKE_C_LINK_EXECUTABLE)
|
||||
|
|
|
@ -201,7 +201,7 @@ ENDIF(NOT CMAKE_CXX_CREATE_STATIC_LIBRARY)
|
|||
# compile a C++ file into an object file
|
||||
IF(NOT CMAKE_CXX_COMPILE_OBJECT)
|
||||
SET(CMAKE_CXX_COMPILE_OBJECT
|
||||
"<CMAKE_CXX_COMPILER> <FLAGS> -o <OBJECT> -c <SOURCE>")
|
||||
"<CMAKE_CXX_COMPILER> <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>")
|
||||
ENDIF(NOT CMAKE_CXX_COMPILE_OBJECT)
|
||||
|
||||
IF(NOT CMAKE_CXX_LINK_EXECUTABLE)
|
||||
|
|
|
@ -33,15 +33,15 @@ ELSE(CMAKE_COMPILER_IS_GNUCC)
|
|||
ENDIF(CMAKE_COMPILER_IS_GNUCC)
|
||||
|
||||
IF(NOT CMAKE_COMPILER_IS_GNUCC)
|
||||
SET (CMAKE_C_CREATE_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
||||
SET (CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
|
||||
SET (CMAKE_C_CREATE_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
||||
SET (CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
|
||||
ENDIF(NOT CMAKE_COMPILER_IS_GNUCC)
|
||||
|
||||
IF(NOT CMAKE_COMPILER_IS_GNUCXX)
|
||||
SET(CMAKE_CXX_COMPILE_OBJECT
|
||||
"<CMAKE_CXX_COMPILER> -+ <FLAGS> -o <OBJECT> -c <SOURCE>")
|
||||
SET (CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
||||
SET (CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
|
||||
"<CMAKE_CXX_COMPILER> -+ <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>")
|
||||
SET (CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
||||
SET (CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
|
||||
ENDIF(NOT CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ IF(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_INIT)
|
|||
ENDIF(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_INIT)
|
||||
|
||||
# compile a C file into an object file
|
||||
SET(CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> <FLAGS> -o <OBJECT> -c <SOURCE>")
|
||||
SET(CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>")
|
||||
|
||||
# link object files to an executable
|
||||
SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <OBJECTS> --out-fmt-ihx -o <TARGET> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>")
|
||||
|
|
|
@ -28,6 +28,6 @@ FOREACH(type SHARED_LIBRARY SHARED_MODULE EXE)
|
|||
ENDFOREACH(type)
|
||||
# force the language to be c++ since qnx only has gcc and not g++ and c++?
|
||||
SET(CMAKE_CXX_COMPILE_OBJECT
|
||||
"<CMAKE_CXX_COMPILER> -x c++ <FLAGS> -o <OBJECT> -c <SOURCE>")
|
||||
"<CMAKE_CXX_COMPILER> -x c++ <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>")
|
||||
|
||||
INCLUDE(Platform/UnixPaths)
|
||||
|
|
|
@ -63,12 +63,16 @@ SET(CMAKE_CXX_CREATE_STATIC_LIBRARY "tlib ${CMAKE_START_TEMP_FILE}/p512 <LINK_F
|
|||
SET(CMAKE_C_CREATE_STATIC_LIBRARY ${CMAKE_CXX_CREATE_STATIC_LIBRARY})
|
||||
|
||||
# compile a C++ file into an object file
|
||||
# place <DEFINES> outside the response file because Borland refuses
|
||||
# to parse quotes from the response file.
|
||||
SET(CMAKE_CXX_COMPILE_OBJECT
|
||||
"<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE}-DWIN32 -P <FLAGS> -o<OBJECT> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
"<CMAKE_CXX_COMPILER> <DEFINES> ${CMAKE_START_TEMP_FILE}-DWIN32 -P <FLAGS> -o<OBJECT> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
# compile a C file into an object file
|
||||
# place <DEFINES> outside the response file because Borland refuses
|
||||
# to parse quotes from the response file.
|
||||
SET(CMAKE_C_COMPILE_OBJECT
|
||||
"<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE}-DWIN32 -o<OBJECT> <FLAGS> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
"<CMAKE_C_COMPILER> <DEFINES> ${CMAKE_START_TEMP_FILE}-DWIN32 -o<OBJECT> <FLAGS> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
|
||||
SET(CMAKE_C_LINK_EXECUTABLE
|
||||
|
|
|
@ -27,11 +27,11 @@ SET(CMAKE_C_CREATE_STATIC_LIBRARY ${CMAKE_CXX_CREATE_STATIC_LIBRARY})
|
|||
|
||||
# compile a C++ file into an object file
|
||||
SET(CMAKE_CXX_COMPILE_OBJECT
|
||||
"<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /TP -DWIN32 /Fo<OBJECT> <FLAGS> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
"<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /TP -DWIN32 /Fo<OBJECT> <DEFINES> <FLAGS> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
# compile a C file into an object file
|
||||
SET(CMAKE_C_COMPILE_OBJECT
|
||||
"<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} -DWIN32 /Fo<OBJECT> <FLAGS> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
"<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} -DWIN32 /Fo<OBJECT> <DEFINES> <FLAGS> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
|
||||
SET(CMAKE_C_LINK_EXECUTABLE
|
||||
|
|
|
@ -36,19 +36,19 @@ SET(CMAKE_CXX_LINK_EXECUTABLE ${CMAKE_C_LINK_EXECUTABLE})
|
|||
|
||||
# compile a C++ file into an object file
|
||||
SET(CMAKE_CXX_COMPILE_OBJECT
|
||||
"<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -fo<OBJECT> -c -cc++ <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
"<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -d+ <DEFINES> -fo<OBJECT> -c -cc++ <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
# compile a C file into an object file
|
||||
SET(CMAKE_C_COMPILE_OBJECT
|
||||
"<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -fo<OBJECT> -c -cc <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
"<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -d+ <DEFINES> -fo<OBJECT> -c -cc <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
# preprocess a C source file
|
||||
SET(CMAKE_C_CREATE_PREPROCESSED_SOURCE
|
||||
"<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -fo<PREPROCESSED_SOURCE> -pl -cc <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
"<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -d+ <DEFINES> -fo<PREPROCESSED_SOURCE> -pl -cc <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
# preprocess a C++ source file
|
||||
SET(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE
|
||||
"<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -fo<PREPROCESSED_SOURCE> -pl -cc++ <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
"<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -d+ <DEFINES> -fo<PREPROCESSED_SOURCE> -pl -cc++ <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
SET(CMAKE_CXX_CREATE_SHARED_MODULE
|
||||
"wlink ${CMAKE_START_TEMP_FILE} system nt_dll ${CMAKE_WLINK_QUIET} name <TARGET> option caseexact file {<OBJECTS>} <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
|
||||
|
|
|
@ -34,11 +34,11 @@ SET(CMAKE_C_CREATE_STATIC_LIBRARY "${CMAKE_CXX_CREATE_STATIC_LIBRARY}")
|
|||
|
||||
# compile a C++ file into an object file
|
||||
SET(CMAKE_CXX_COMPILE_OBJECT
|
||||
"<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> /TP /Fo<OBJECT> /Fd<TARGET_PDB> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
"<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> <DEFINES> /TP /Fo<OBJECT> /Fd<TARGET_PDB> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
# compile a C file into an object file
|
||||
SET(CMAKE_C_COMPILE_OBJECT
|
||||
"<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> /Fo<OBJECT> /Fd<TARGET_PDB> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
"<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> <DEFINES> /Fo<OBJECT> /Fd<TARGET_PDB> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
|
||||
SET(CMAKE_C_LINK_EXECUTABLE
|
||||
|
@ -48,10 +48,10 @@ SET(CMAKE_CXX_LINK_EXECUTABLE
|
|||
"<CMAKE_CXX_COMPILER> ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} <FLAGS> <OBJECTS> /Fe<TARGET> /Fd<TARGET_PDB> -link /implib:<TARGET_IMPLIB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
SET(CMAKE_C_CREATE_PREPROCESSED_SOURCE
|
||||
"<CMAKE_C_COMPILER> > <PREPROCESSED_SOURCE> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> -E <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
"<CMAKE_C_COMPILER> > <PREPROCESSED_SOURCE> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> <DEFINES> -E <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
SET(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE
|
||||
"<CMAKE_CXX_COMPILER> > <PREPROCESSED_SOURCE> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> /TP -E <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
"<CMAKE_CXX_COMPILER> > <PREPROCESSED_SOURCE> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> <DEFINES> /TP -E <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
||||
SET(CMAKE_C_CREATE_ASSEMBLY_SOURCE
|
||||
"<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> /FAs /FoNUL /Fa<ASSEMBLY_SOURCE> /c <SOURCE>${CMAKE_END_TEMP_FILE}")
|
||||
|
|
|
@ -453,6 +453,9 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
|
|||
lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS"));
|
||||
cmSystemTools::ReplaceString(flags, "\"", "\\\"");
|
||||
|
||||
// Add per-source definitions.
|
||||
this->AppendDefines(flags, sf->GetProperty("COMPILE_DEFINITIONS"), true);
|
||||
|
||||
// Using a map and the full path guarantees that we will always get the same
|
||||
// fileRef object for any given full path.
|
||||
//
|
||||
|
@ -1260,12 +1263,6 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
|
|||
bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
|
||||
(target.GetType() == cmTarget::MODULE_LIBRARY));
|
||||
|
||||
// Add the export symbol definition for shared library objects.
|
||||
if(const char* exportMacro = target.GetExportMacro())
|
||||
{
|
||||
defFlags += "-D";
|
||||
defFlags += exportMacro;
|
||||
}
|
||||
const char* lang = target.GetLinkerLanguage(this);
|
||||
std::string cflags;
|
||||
if(lang)
|
||||
|
@ -1291,12 +1288,28 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
|
|||
cmSystemTools::ReplaceString(defFlags, "\"", "\\\"");
|
||||
cmSystemTools::ReplaceString(flags, "\"", "\\\"");
|
||||
cmSystemTools::ReplaceString(cflags, "\"", "\\\"");
|
||||
|
||||
// Add preprocessor definitions for this target and configuration.
|
||||
std::string ppDefs;
|
||||
if(this->XcodeVersion > 15)
|
||||
{
|
||||
buildSettings->AddAttribute
|
||||
("GCC_PREPROCESSOR_DEFINITIONS",
|
||||
this->CreateString("CMAKE_INTDIR=\\\\\"$(CONFIGURATION)\\\\\""));
|
||||
this->AppendDefines(ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)\"");
|
||||
}
|
||||
if(const char* exportMacro = target.GetExportMacro())
|
||||
{
|
||||
// Add the export symbol definition for shared library objects.
|
||||
this->AppendDefines(ppDefs, exportMacro);
|
||||
}
|
||||
this->AppendDefines(ppDefs, target.GetProperty("COMPILE_DEFINITIONS"));
|
||||
if(configName)
|
||||
{
|
||||
std::string defVarName = cmSystemTools::UpperCase(configName);
|
||||
defVarName += "_COMPILE_DEFINITIONS";
|
||||
this->AppendDefines(ppDefs, target.GetProperty(defVarName.c_str()));
|
||||
}
|
||||
buildSettings->AddAttribute
|
||||
("GCC_PREPROCESSOR_DEFINITIONS", this->CreateString(ppDefs.c_str()));
|
||||
|
||||
std::string extraLinkOptions;
|
||||
if(target.GetType() == cmTarget::EXECUTABLE)
|
||||
{
|
||||
|
@ -2887,3 +2900,64 @@ std::string cmGlobalXCodeGenerator::LookupFlags(const char* varNamePrefix,
|
|||
}
|
||||
return default_flags;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmGlobalXCodeGenerator::AppendDefines(std::string& defs,
|
||||
const char* defines_list,
|
||||
bool dflag)
|
||||
{
|
||||
// Skip this if there are no definitions.
|
||||
if(!defines_list)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Expand the list of definitions.
|
||||
std::vector<std::string> defines;
|
||||
cmSystemTools::ExpandListArgument(defines_list, defines);
|
||||
|
||||
// GCC_PREPROCESSOR_DEFINITIONS is a space-separated list of definitions.
|
||||
// We escape everything as follows:
|
||||
// - Place each definition in single quotes ''
|
||||
// - Escape a single quote as \\'
|
||||
// - Escape a backslash as \\\\
|
||||
// Note that in the code below we need one more level of escapes for
|
||||
// C string syntax in this source file.
|
||||
const char* sep = defs.empty()? "" : " ";
|
||||
for(std::vector<std::string>::const_iterator di = defines.begin();
|
||||
di != defines.end(); ++di)
|
||||
{
|
||||
// Separate from previous definition.
|
||||
defs += sep;
|
||||
sep = " ";
|
||||
|
||||
// Open single quote.
|
||||
defs += "'";
|
||||
|
||||
// Add -D flag if requested.
|
||||
if(dflag)
|
||||
{
|
||||
defs += "-D";
|
||||
}
|
||||
|
||||
// Escaped definition string.
|
||||
for(const char* c = di->c_str(); *c; ++c)
|
||||
{
|
||||
if(*c == '\'')
|
||||
{
|
||||
defs += "\\\\'";
|
||||
}
|
||||
else if(*c == '\\')
|
||||
{
|
||||
defs += "\\\\\\\\";
|
||||
}
|
||||
else
|
||||
{
|
||||
defs += *c;
|
||||
}
|
||||
}
|
||||
|
||||
// Close single quote.
|
||||
defs += "'";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,6 +173,9 @@ private:
|
|||
const char* varNameSuffix,
|
||||
const char* default_flags);
|
||||
|
||||
void AppendDefines(std::string& defs, const char* defines_list,
|
||||
bool dflag = false);
|
||||
|
||||
protected:
|
||||
virtual const char* GetInstallTargetName() { return "install"; }
|
||||
virtual const char* GetPackageTargetName() { return "package"; }
|
||||
|
|
|
@ -856,6 +856,10 @@ cmLocalGenerator::ExpandRuleVariable(std::string const& variable,
|
|||
return replaceValues.ObjectsQuoted;
|
||||
}
|
||||
}
|
||||
if(replaceValues.Defines && variable == "DEFINES")
|
||||
{
|
||||
return replaceValues.Defines;
|
||||
}
|
||||
if(replaceValues.TargetPDB )
|
||||
{
|
||||
if(variable == "TARGET_PDB")
|
||||
|
@ -2213,6 +2217,77 @@ void cmLocalGenerator::AppendFlags(std::string& flags,
|
|||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmLocalGenerator::AppendDefines(std::string& defines,
|
||||
const char* defines_list)
|
||||
{
|
||||
// Short-circuit if there are no definitions.
|
||||
if(!defines_list)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Expand the list of definitions.
|
||||
std::vector<std::string> defines_vec;
|
||||
cmSystemTools::ExpandListArgument(defines_list, defines_vec);
|
||||
|
||||
// Short-circuit if there are no definitions.
|
||||
if(defines_vec.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Separate from previous definitions with a space.
|
||||
if(!defines.empty())
|
||||
{
|
||||
defines += " ";
|
||||
}
|
||||
|
||||
// Add each definition to the command line with appropriate escapes.
|
||||
const char* dsep = "-D";
|
||||
for(std::vector<std::string>::const_iterator di = defines_vec.begin();
|
||||
di != defines_vec.end(); ++di)
|
||||
{
|
||||
// Skip unsupported definitions.
|
||||
if(!this->CheckDefinition(*di))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Append the -D
|
||||
defines += dsep;
|
||||
|
||||
// Append the definition with proper escaping.
|
||||
if(this->WatcomWMake)
|
||||
{
|
||||
// The Watcom compiler does its own command line parsing instead
|
||||
// of using the windows shell rules. Definitions are one of
|
||||
// -DNAME
|
||||
// -DNAME=<cpp-token>
|
||||
// -DNAME="c-string with spaces and other characters(?@#$)"
|
||||
//
|
||||
// Watcom will properly parse each of these cases from the
|
||||
// command line without any escapes. However we still have to
|
||||
// get the '$' and '#' characters through WMake as '$$' and
|
||||
// '$#'.
|
||||
for(const char* c = di->c_str(); *c; ++c)
|
||||
{
|
||||
if(*c == '$' || *c == '#')
|
||||
{
|
||||
defines += '$';
|
||||
}
|
||||
defines += *c;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make the definition appear properly on the command line.
|
||||
defines += this->EscapeForShell(di->c_str(), true);
|
||||
}
|
||||
dsep = " -D";
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::string
|
||||
cmLocalGenerator::ConstructComment(const cmCustomCommand& cc,
|
||||
|
@ -2963,3 +3038,45 @@ bool cmLocalGenerator::NeedBackwardsCompatibility(unsigned int major,
|
|||
return (actual_compat &&
|
||||
actual_compat <= CMake_VERSION_ENCODE(major, minor, patch));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool cmLocalGenerator::CheckDefinition(std::string const& define) const
|
||||
{
|
||||
// Many compilers do not support -DNAME(arg)=sdf so we disable it.
|
||||
bool function_style = false;
|
||||
for(const char* c = define.c_str(); *c && *c != '='; ++c)
|
||||
{
|
||||
if(*c == '(')
|
||||
{
|
||||
function_style = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(function_style)
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "WARNING: Function-style preprocessor definitions may not be "
|
||||
<< "passed on the compiler command line because many compilers "
|
||||
<< "do not support it.\n"
|
||||
<< "CMake is dropping a preprocessor definition: " << define << "\n"
|
||||
<< "Consider defining the macro in a (configured) header file.\n";
|
||||
cmSystemTools::Message(e.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Many compilers do not support # in the value so we disable it.
|
||||
if(define.find_first_of("#") != define.npos)
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "WARNING: Peprocessor definitions containing '#' may not be "
|
||||
<< "passed on the compiler command line because many compilers "
|
||||
<< "do not support it.\n"
|
||||
<< "CMake is dropping a preprocessor definition: " << define << "\n"
|
||||
<< "Consider defining the macro in a (configured) header file.\n";
|
||||
cmSystemTools::Message(e.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assume it is supported.
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -139,6 +139,12 @@ public:
|
|||
///! Get the include flags for the current makefile and language
|
||||
const char* GetIncludeFlags(const char* lang);
|
||||
|
||||
/**
|
||||
* Encode a list of preprocessor definitions for the compiler
|
||||
* command line.
|
||||
*/
|
||||
void AppendDefines(std::string& defines, const char* defines_list);
|
||||
|
||||
/** Translate a dependency as given in CMake code to the name to
|
||||
appear in a generated build file. If the given name is that of
|
||||
a CMake target it will be transformed to the real output
|
||||
|
@ -207,6 +213,7 @@ public:
|
|||
const char* TargetInstallNameDir;
|
||||
const char* LinkFlags;
|
||||
const char* LanguageCompileFlags;
|
||||
const char* Defines;
|
||||
};
|
||||
|
||||
/** Escape the given string to be used as a command line argument in
|
||||
|
@ -324,6 +331,10 @@ protected:
|
|||
std::string FindRelativePathTopBinary();
|
||||
void SetupPathConversions();
|
||||
|
||||
/** Check whether the native build system supports the given
|
||||
definition. Issues a warning. */
|
||||
virtual bool CheckDefinition(std::string const& define) const;
|
||||
|
||||
cmMakefile *Makefile;
|
||||
cmGlobalGenerator *GlobalGenerator;
|
||||
// members used for relative path function ConvertToMakefilePath
|
||||
|
|
|
@ -338,17 +338,9 @@ cmLocalUnixMakefileGenerator3
|
|||
// Add a rule to drive the rule below.
|
||||
std::vector<std::string> depends;
|
||||
depends.push_back(output);
|
||||
std::vector<std::string> commands;
|
||||
cmGlobalUnixMakefileGenerator3* gg =
|
||||
static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
|
||||
std::string emptyCommand = gg->GetEmptyRuleHackCommand();
|
||||
if(!emptyCommand.empty())
|
||||
{
|
||||
commands.push_back(emptyCommand);
|
||||
}
|
||||
|
||||
std::vector<std::string> no_commands;
|
||||
this->WriteMakeRule(ruleFileStream, 0,
|
||||
outNoExt.c_str(), depends, commands, true, true);
|
||||
outNoExt.c_str(), depends, no_commands, true, true);
|
||||
inHelp = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -413,6 +413,29 @@ void cmLocalVisualStudio6Generator
|
|||
compileFlags += cflags;
|
||||
}
|
||||
|
||||
// Add per-source and per-configuration preprocessor definitions.
|
||||
std::map<cmStdString, cmStdString> cdmap;
|
||||
this->AppendDefines(compileFlags,
|
||||
(*sf)->GetProperty("COMPILE_DEFINITIONS"));
|
||||
if(const char* cdefs = (*sf)->GetProperty("DEBUG_COMPILE_DEFINITIONS"))
|
||||
{
|
||||
this->AppendDefines(cdmap["DEBUG"], cdefs);
|
||||
}
|
||||
if(const char* cdefs = (*sf)->GetProperty("RELEASE_COMPILE_DEFINITIONS"))
|
||||
{
|
||||
this->AppendDefines(cdmap["RELEASE"], cdefs);
|
||||
}
|
||||
if(const char* cdefs =
|
||||
(*sf)->GetProperty("MINSIZEREL_COMPILE_DEFINITIONS"))
|
||||
{
|
||||
this->AppendDefines(cdmap["MINSIZEREL"], cdefs);
|
||||
}
|
||||
if(const char* cdefs =
|
||||
(*sf)->GetProperty("RELWITHDEBINFO_COMPILE_DEFINITIONS"))
|
||||
{
|
||||
this->AppendDefines(cdmap["RELWITHDEBINFO"], cdefs);
|
||||
}
|
||||
|
||||
const char* lang = this->GetSourceFileLanguage(*(*sf));
|
||||
if(lang)
|
||||
{
|
||||
|
@ -464,12 +487,14 @@ void cmLocalVisualStudio6Generator
|
|||
this->WriteCustomRule(fout, source.c_str(), *command, flags);
|
||||
}
|
||||
else if(!compileFlags.empty() || !objectNameDir.empty() ||
|
||||
excludedFromBuild)
|
||||
excludedFromBuild || !cdmap.empty())
|
||||
{
|
||||
for(std::vector<std::string>::iterator i
|
||||
= this->Configurations.begin();
|
||||
i != this->Configurations.end(); ++i)
|
||||
{
|
||||
// Strip the subdirectory name out of the configuration name.
|
||||
std::string config = this->GetConfigName(*i);
|
||||
if (i == this->Configurations.begin())
|
||||
{
|
||||
fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl;
|
||||
|
@ -486,11 +511,14 @@ void cmLocalVisualStudio6Generator
|
|||
{
|
||||
fout << "\n# ADD CPP " << compileFlags << "\n\n";
|
||||
}
|
||||
std::map<cmStdString, cmStdString>::iterator cdi =
|
||||
cdmap.find(cmSystemTools::UpperCase(config));
|
||||
if(cdi != cdmap.end() && !cdi->second.empty())
|
||||
{
|
||||
fout << "\n# ADD CPP " << cdi->second << "\n\n";
|
||||
}
|
||||
if(!objectNameDir.empty())
|
||||
{
|
||||
// Strip the subdirectory name out of the configuration name.
|
||||
std::string config = this->GetConfigName(*i);
|
||||
|
||||
// Setup an alternate object file directory.
|
||||
fout << "\n# PROP Intermediate_Dir \""
|
||||
<< config << "/" << objectNameDir << "\"\n\n";
|
||||
|
@ -1474,6 +1502,19 @@ void cmLocalVisualStudio6Generator
|
|||
flags += targetFlags;
|
||||
}
|
||||
|
||||
// Add per-target and per-configuration preprocessor definitions.
|
||||
this->AppendDefines(flags, target.GetProperty("COMPILE_DEFINITIONS"));
|
||||
this->AppendDefines(flagsDebug,
|
||||
target.GetProperty("DEBUG_COMPILE_DEFINITIONS"));
|
||||
this->AppendDefines(flagsRelease,
|
||||
target.GetProperty("RELEASE_COMPILE_DEFINITIONS"));
|
||||
this->AppendDefines
|
||||
(flagsMinSize,
|
||||
target.GetProperty("MINSIZEREL_COMPILE_DEFINITIONS"));
|
||||
this->AppendDefines
|
||||
(flagsDebugRel,
|
||||
target.GetProperty("RELWITHDEBINFO_COMPILE_DEFINITIONS"));
|
||||
|
||||
// The template files have CXX FLAGS in them, that need to be replaced.
|
||||
// There are not separate CXX and C template files, so we use the same
|
||||
// variable names. The previous code sets up flags* variables to contain
|
||||
|
@ -1584,3 +1625,30 @@ cmLocalVisualStudio6Generator
|
|||
config = config.substr(0, config.size()-1);
|
||||
return config;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
cmLocalVisualStudio6Generator
|
||||
::CheckDefinition(std::string const& define) const
|
||||
{
|
||||
// Perform the standard check first.
|
||||
if(!this->cmLocalGenerator::CheckDefinition(define))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now do the VS6-specific check.
|
||||
if(define.find_first_of("=") != define.npos)
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "WARNING: The VS6 IDE does not support preprocessor definitions "
|
||||
<< "with values.\n"
|
||||
<< "CMake is dropping a preprocessor definition: " << define << "\n"
|
||||
<< "Consider defining the macro in a (configured) header file.\n";
|
||||
cmSystemTools::Message(e.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assume it is supported.
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -103,6 +103,9 @@ private:
|
|||
std::vector<std::string> Configurations;
|
||||
|
||||
std::string GetConfigName(std::string const& configuration) const;
|
||||
|
||||
// Special definition check for VS6.
|
||||
virtual bool CheckDefinition(std::string const& define) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -384,7 +384,8 @@ public:
|
|||
Compiler,
|
||||
Linker
|
||||
};
|
||||
cmLocalVisualStudio7GeneratorOptions(Tool tool,
|
||||
cmLocalVisualStudio7GeneratorOptions(cmLocalVisualStudio7Generator* lg,
|
||||
Tool tool,
|
||||
cmVS7FlagTable const* extraTable = 0);
|
||||
|
||||
// Store options from command line flags.
|
||||
|
@ -398,6 +399,7 @@ public:
|
|||
|
||||
// Store definitions and flags.
|
||||
void AddDefine(const std::string& define);
|
||||
void AddDefines(const char* defines);
|
||||
void AddFlag(const char* flag, const char* value);
|
||||
|
||||
// Check for specific options.
|
||||
|
@ -413,6 +415,8 @@ public:
|
|||
const char* suffix);
|
||||
|
||||
private:
|
||||
cmLocalVisualStudio7Generator* LocalGenerator;
|
||||
|
||||
// create a map of xml tags to the values they should have in the output
|
||||
// for example, "BufferSecurityCheck" = "TRUE"
|
||||
// first fill this table with the values for the configuration
|
||||
|
@ -423,7 +427,7 @@ private:
|
|||
std::map<cmStdString, cmStdString> FlagMap;
|
||||
|
||||
// Preprocessor definitions.
|
||||
std::vector<cmStdString> Defines;
|
||||
std::vector<std::string> Defines;
|
||||
|
||||
// Unrecognized flags that get no special handling.
|
||||
cmStdString FlagString;
|
||||
|
@ -516,14 +520,20 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
|
|||
flags += targetFlags;
|
||||
}
|
||||
|
||||
std::string configUpper = cmSystemTools::UpperCase(configName);
|
||||
std::string defPropName = configUpper;
|
||||
defPropName += "_COMPILE_DEFINITIONS";
|
||||
|
||||
// Get preprocessor definitions for this directory.
|
||||
std::string defineFlags = this->Makefile->GetDefineFlags();
|
||||
|
||||
// Construct a set of build options for this target.
|
||||
Options targetOptions(Options::Compiler, this->ExtraFlagTable);
|
||||
Options targetOptions(this, Options::Compiler, this->ExtraFlagTable);
|
||||
targetOptions.FixExceptionHandlingDefault();
|
||||
targetOptions.Parse(flags.c_str());
|
||||
targetOptions.Parse(defineFlags.c_str());
|
||||
targetOptions.AddDefines(target.GetProperty("COMPILE_DEFINITIONS"));
|
||||
targetOptions.AddDefines(target.GetProperty(defPropName.c_str()));
|
||||
targetOptions.SetVerboseMakefile(
|
||||
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
|
||||
|
||||
|
@ -703,7 +713,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
|
|||
extraLinkOptions += " ";
|
||||
extraLinkOptions += targetLinkFlags;
|
||||
}
|
||||
Options linkOptions(Options::Linker);
|
||||
Options linkOptions(this, Options::Linker);
|
||||
linkOptions.Parse(extraLinkOptions.c_str());
|
||||
switch(target.GetType())
|
||||
{
|
||||
|
@ -1027,6 +1037,135 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
|
|||
this->WriteVCProjFooter(fout);
|
||||
}
|
||||
|
||||
struct cmLVS7GFileConfig
|
||||
{
|
||||
std::string ObjectName;
|
||||
std::string CompileFlags;
|
||||
std::string CompileDefs;
|
||||
std::string CompileDefsConfig;
|
||||
std::string AdditionalDeps;
|
||||
bool ExcludedFromBuild;
|
||||
};
|
||||
|
||||
class cmLocalVisualStudio7GeneratorFCInfo
|
||||
{
|
||||
public:
|
||||
cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg,
|
||||
cmTarget& target,
|
||||
cmSourceFile const& sf,
|
||||
std::vector<std::string>* configs,
|
||||
std::string::size_type dir_len);
|
||||
std::map<cmStdString, cmLVS7GFileConfig> FileConfigMap;
|
||||
};
|
||||
|
||||
cmLocalVisualStudio7GeneratorFCInfo
|
||||
::cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg,
|
||||
cmTarget& target,
|
||||
cmSourceFile const& sf,
|
||||
std::vector<std::string>* configs,
|
||||
std::string::size_type dir_len)
|
||||
{
|
||||
std::string objectName;
|
||||
if(lg->NeedObjectName.find(&sf) != lg->NeedObjectName.end())
|
||||
{
|
||||
objectName = lg->GetObjectFileNameWithoutTarget(sf, dir_len);
|
||||
}
|
||||
|
||||
// Compute per-source, per-config information.
|
||||
for(std::vector<std::string>::iterator i = configs->begin();
|
||||
i != configs->end(); ++i)
|
||||
{
|
||||
std::string configUpper = cmSystemTools::UpperCase(*i);
|
||||
cmLVS7GFileConfig fc;
|
||||
bool needfc = false;
|
||||
if(!objectName.empty())
|
||||
{
|
||||
fc.ObjectName = objectName;
|
||||
needfc = true;
|
||||
}
|
||||
if(const char* cflags = sf.GetProperty("COMPILE_FLAGS"))
|
||||
{
|
||||
fc.CompileFlags = cflags;
|
||||
needfc = true;
|
||||
}
|
||||
if(const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS"))
|
||||
{
|
||||
fc.CompileDefs = cdefs;
|
||||
needfc = true;
|
||||
}
|
||||
std::string defPropName = configUpper;
|
||||
defPropName += "_COMPILE_DEFINITIONS";
|
||||
if(const char* ccdefs = sf.GetProperty(defPropName.c_str()))
|
||||
{
|
||||
fc.CompileDefsConfig = ccdefs;
|
||||
needfc = true;
|
||||
}
|
||||
|
||||
// Check for extra object-file dependencies.
|
||||
if(const char* deps = sf.GetProperty("OBJECT_DEPENDS"))
|
||||
{
|
||||
std::vector<std::string> depends;
|
||||
cmSystemTools::ExpandListArgument(deps, depends);
|
||||
const char* sep = "";
|
||||
for(std::vector<std::string>::iterator j = depends.begin();
|
||||
j != depends.end(); ++j)
|
||||
{
|
||||
fc.AdditionalDeps += sep;
|
||||
fc.AdditionalDeps += lg->ConvertToXMLOutputPath(j->c_str());
|
||||
sep = ";";
|
||||
needfc = true;
|
||||
}
|
||||
}
|
||||
|
||||
const char* lang =
|
||||
lg->GlobalGenerator->GetLanguageFromExtension
|
||||
(sf.GetExtension().c_str());
|
||||
const char* sourceLang = lg->GetSourceFileLanguage(sf);
|
||||
const char* linkLanguage = target.GetLinkerLanguage
|
||||
(lg->GetGlobalGenerator());
|
||||
bool needForceLang = false;
|
||||
// source file does not match its extension language
|
||||
if(lang && sourceLang && strcmp(lang, sourceLang) != 0)
|
||||
{
|
||||
needForceLang = true;
|
||||
lang = sourceLang;
|
||||
}
|
||||
// If lang is set, the compiler will generate code automatically.
|
||||
// If HEADER_FILE_ONLY is set, we must suppress this generation in
|
||||
// the project file
|
||||
fc.ExcludedFromBuild =
|
||||
(lang && sf.GetPropertyAsBool("HEADER_FILE_ONLY"));
|
||||
if(fc.ExcludedFromBuild)
|
||||
{
|
||||
needfc = true;
|
||||
}
|
||||
|
||||
// if the source file does not match the linker language
|
||||
// then force c or c++
|
||||
if(needForceLang || (linkLanguage && lang
|
||||
&& strcmp(lang, linkLanguage) != 0))
|
||||
{
|
||||
if(strcmp(lang, "CXX") == 0)
|
||||
{
|
||||
// force a C++ file type
|
||||
fc.CompileFlags += " /TP ";
|
||||
needfc = true;
|
||||
}
|
||||
else if(strcmp(lang, "C") == 0)
|
||||
{
|
||||
// force to c
|
||||
fc.CompileFlags += " /TC ";
|
||||
needfc = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(needfc)
|
||||
{
|
||||
this->FileConfigMap[*i] = fc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmLocalVisualStudio7Generator
|
||||
::WriteGroup(const cmSourceGroup *sg, cmTarget target,
|
||||
std::ostream &fout, const char *libName,
|
||||
|
@ -1075,76 +1214,8 @@ void cmLocalVisualStudio7Generator
|
|||
sourceFiles.begin(); sf != sourceFiles.end(); ++sf)
|
||||
{
|
||||
std::string source = (*sf)->GetFullPath();
|
||||
const cmCustomCommand *command = (*sf)->GetCustomCommand();
|
||||
std::string compileFlags;
|
||||
std::string additionalDeps;
|
||||
if(this->NeedObjectName.find(*sf) != this->NeedObjectName.end())
|
||||
{
|
||||
objectName = this->GetObjectFileNameWithoutTarget(*(*sf), dir_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
objectName = "";
|
||||
}
|
||||
// Add per-source flags.
|
||||
const char* cflags = (*sf)->GetProperty("COMPILE_FLAGS");
|
||||
if(cflags)
|
||||
{
|
||||
compileFlags += " ";
|
||||
compileFlags += cflags;
|
||||
}
|
||||
const char* lang =
|
||||
this->GlobalGenerator->GetLanguageFromExtension
|
||||
((*sf)->GetExtension().c_str());
|
||||
const char* sourceLang = this->GetSourceFileLanguage(*(*sf));
|
||||
const char* linkLanguage = target.GetLinkerLanguage
|
||||
(this->GetGlobalGenerator());
|
||||
bool needForceLang = false;
|
||||
// source file does not match its extension language
|
||||
if(lang && sourceLang && strcmp(lang, sourceLang) != 0)
|
||||
{
|
||||
needForceLang = true;
|
||||
lang = sourceLang;
|
||||
}
|
||||
// If lang is set, the compiler will generate code automatically.
|
||||
// If HEADER_FILE_ONLY is set, we must suppress this generation in
|
||||
// the project file
|
||||
bool excludedFromBuild =
|
||||
(lang && (*sf)->GetPropertyAsBool("HEADER_FILE_ONLY"));
|
||||
FCInfo fcinfo(this, target, *(*sf), configs, dir_len);
|
||||
|
||||
// if the source file does not match the linker language
|
||||
// then force c or c++
|
||||
if(needForceLang || (linkLanguage && lang
|
||||
&& strcmp(lang, linkLanguage) != 0))
|
||||
{
|
||||
if(strcmp(lang, "CXX") == 0)
|
||||
{
|
||||
// force a C++ file type
|
||||
compileFlags += " /TP ";
|
||||
}
|
||||
else if(strcmp(lang, "C") == 0)
|
||||
{
|
||||
// force to c
|
||||
compileFlags += " /TC ";
|
||||
}
|
||||
}
|
||||
// Check for extra object-file dependencies.
|
||||
const char* deps = (*sf)->GetProperty("OBJECT_DEPENDS");
|
||||
if(deps)
|
||||
{
|
||||
std::vector<std::string> depends;
|
||||
cmSystemTools::ExpandListArgument(deps, depends);
|
||||
if(!depends.empty())
|
||||
{
|
||||
std::vector<std::string>::iterator i = depends.begin();
|
||||
additionalDeps = this->ConvertToXMLOutputPath(i->c_str());
|
||||
for(++i;i != depends.end(); ++i)
|
||||
{
|
||||
additionalDeps += ";";
|
||||
additionalDeps += this->ConvertToXMLOutputPath(i->c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (source != libName || target.GetType() == cmTarget::UTILITY ||
|
||||
target.GetType() == cmTarget::GLOBAL_TARGET )
|
||||
{
|
||||
|
@ -1153,13 +1224,11 @@ void cmLocalVisualStudio7Generator
|
|||
// Tell MS-Dev what the source is. If the compiler knows how to
|
||||
// build it, then it will.
|
||||
fout << "\t\t\t\tRelativePath=\"" << d << "\">\n";
|
||||
if (command)
|
||||
if(cmCustomCommand const* command = (*sf)->GetCustomCommand())
|
||||
{
|
||||
const char* flags = compileFlags.size() ? compileFlags.c_str(): 0;
|
||||
this->WriteCustomRule(fout, source.c_str(), *command, flags);
|
||||
this->WriteCustomRule(fout, source.c_str(), *command, fcinfo);
|
||||
}
|
||||
else if(compileFlags.size() || additionalDeps.length()
|
||||
|| objectName.size() || excludedFromBuild)
|
||||
else if(!fcinfo.FileConfigMap.empty())
|
||||
{
|
||||
const char* aCompilerTool = "VCCLCompilerTool";
|
||||
std::string ext = (*sf)->GetExtension();
|
||||
|
@ -1176,37 +1245,44 @@ void cmLocalVisualStudio7Generator
|
|||
{
|
||||
aCompilerTool = "VCCustomBuildTool";
|
||||
}
|
||||
for(std::vector<std::string>::iterator i = configs->begin();
|
||||
i != configs->end(); ++i)
|
||||
for(std::map<cmStdString, cmLVS7GFileConfig>::const_iterator
|
||||
fci = fcinfo.FileConfigMap.begin();
|
||||
fci != fcinfo.FileConfigMap.end(); ++fci)
|
||||
{
|
||||
cmLVS7GFileConfig const& fc = fci->second;
|
||||
fout << "\t\t\t\t<FileConfiguration\n"
|
||||
<< "\t\t\t\t\tName=\"" << *i
|
||||
<< "\t\t\t\t\tName=\"" << fci->first
|
||||
<< "|" << this->PlatformName << "\"";
|
||||
if(excludedFromBuild)
|
||||
if(fc.ExcludedFromBuild)
|
||||
{
|
||||
fout << " ExcludedFromBuild=\"true\"";
|
||||
}
|
||||
fout << ">\n";
|
||||
fout << "\t\t\t\t\t<Tool\n"
|
||||
<< "\t\t\t\t\tName=\"" << aCompilerTool << "\"\n";
|
||||
if(!compileFlags.empty())
|
||||
if(!fc.CompileFlags.empty() ||
|
||||
!fc.CompileDefs.empty() ||
|
||||
!fc.CompileDefsConfig.empty())
|
||||
{
|
||||
Options fileOptions(Options::Compiler, this->ExtraFlagTable);
|
||||
fileOptions.Parse(compileFlags.c_str());
|
||||
Options fileOptions(this, Options::Compiler,
|
||||
this->ExtraFlagTable);
|
||||
fileOptions.Parse(fc.CompileFlags.c_str());
|
||||
fileOptions.AddDefines(fc.CompileDefs.c_str());
|
||||
fileOptions.AddDefines(fc.CompileDefsConfig.c_str());
|
||||
fileOptions.OutputAdditionalOptions(fout, "\t\t\t\t\t", "\n");
|
||||
fileOptions.OutputFlagMap(fout, "\t\t\t\t\t");
|
||||
fileOptions.OutputPreprocessorDefinitions(fout,
|
||||
"\t\t\t\t\t", "\n");
|
||||
}
|
||||
if(additionalDeps.length())
|
||||
if(!fc.AdditionalDeps.empty())
|
||||
{
|
||||
fout << "\t\t\t\t\tAdditionalDependencies=\""
|
||||
<< additionalDeps.c_str() << "\"\n";
|
||||
<< fc.AdditionalDeps.c_str() << "\"\n";
|
||||
}
|
||||
if(objectName.size())
|
||||
if(!fc.ObjectName.empty())
|
||||
{
|
||||
fout << "\t\t\t\t\tObjectFile=\"$(IntDir)/"
|
||||
<< objectName.c_str() << "\"\n";
|
||||
<< fc.ObjectName.c_str() << "\"\n";
|
||||
}
|
||||
fout << "\t\t\t\t\t/>\n"
|
||||
<< "\t\t\t\t</FileConfiguration>\n";
|
||||
|
@ -1234,7 +1310,7 @@ void cmLocalVisualStudio7Generator::
|
|||
WriteCustomRule(std::ostream& fout,
|
||||
const char* source,
|
||||
const cmCustomCommand& command,
|
||||
const char* compileFlags)
|
||||
FCInfo& fcinfo)
|
||||
{
|
||||
std::string comment = this->ConstructComment(command);
|
||||
|
||||
|
@ -1246,14 +1322,15 @@ WriteCustomRule(std::ostream& fout,
|
|||
|
||||
for(i = configs->begin(); i != configs->end(); ++i)
|
||||
{
|
||||
cmLVS7GFileConfig const& fc = fcinfo.FileConfigMap[*i];
|
||||
fout << "\t\t\t\t<FileConfiguration\n";
|
||||
fout << "\t\t\t\t\tName=\"" << *i << "|" << this->PlatformName << "\">\n";
|
||||
if(compileFlags)
|
||||
if(!fc.CompileFlags.empty())
|
||||
{
|
||||
fout << "\t\t\t\t\t<Tool\n"
|
||||
<< "\t\t\t\t\tName=\"VCCLCompilerTool\"\n"
|
||||
<< "\t\t\t\t\tAdditionalOptions=\""
|
||||
<< this->EscapeForXML(compileFlags) << "\"/>\n";
|
||||
<< this->EscapeForXML(fc.CompileFlags.c_str()) << "\"/>\n";
|
||||
}
|
||||
|
||||
std::string script =
|
||||
|
@ -1659,9 +1736,10 @@ std::string cmLocalVisualStudio7Generator
|
|||
|
||||
//----------------------------------------------------------------------------
|
||||
cmLocalVisualStudio7GeneratorOptions
|
||||
::cmLocalVisualStudio7GeneratorOptions(Tool tool,
|
||||
::cmLocalVisualStudio7GeneratorOptions(cmLocalVisualStudio7Generator* lg,
|
||||
Tool tool,
|
||||
cmVS7FlagTable const* extraTable):
|
||||
CurrentTool(tool),
|
||||
LocalGenerator(lg), CurrentTool(tool),
|
||||
DoingDefine(false), FlagTable(0), ExtraFlagTable(extraTable)
|
||||
{
|
||||
// Choose the flag table for the requested tool.
|
||||
|
@ -1706,6 +1784,16 @@ void cmLocalVisualStudio7GeneratorOptions::AddDefine(const std::string& def)
|
|||
this->Defines.push_back(def);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmLocalVisualStudio7GeneratorOptions::AddDefines(const char* defines)
|
||||
{
|
||||
if(defines)
|
||||
{
|
||||
// Expand the list of definitions.
|
||||
cmSystemTools::ExpandListArgument(defines, this->Defines);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmLocalVisualStudio7GeneratorOptions::AddFlag(const char* flag,
|
||||
const char* value)
|
||||
|
@ -1717,7 +1805,7 @@ void cmLocalVisualStudio7GeneratorOptions::AddFlag(const char* flag,
|
|||
bool cmLocalVisualStudio7GeneratorOptions::UsingUnicode()
|
||||
{
|
||||
// Look for the a _UNICODE definition.
|
||||
for(std::vector<cmStdString>::const_iterator di = this->Defines.begin();
|
||||
for(std::vector<std::string>::const_iterator di = this->Defines.begin();
|
||||
di != this->Defines.end(); ++di)
|
||||
{
|
||||
if(*di == "_UNICODE")
|
||||
|
@ -1886,29 +1974,18 @@ cmLocalVisualStudio7GeneratorOptions
|
|||
|
||||
fout << prefix << "PreprocessorDefinitions=\"";
|
||||
const char* comma = "";
|
||||
for(std::vector<cmStdString>::const_iterator di = this->Defines.begin();
|
||||
for(std::vector<std::string>::const_iterator di = this->Defines.begin();
|
||||
di != this->Defines.end(); ++di)
|
||||
{
|
||||
// Double-quotes in the value of the definition must be escaped
|
||||
// with a backslash.
|
||||
std::string define = di->c_str();
|
||||
cmSystemTools::ReplaceString(define, "\"", "\\\"");
|
||||
// Escape the definition for the compiler.
|
||||
std::string define =
|
||||
this->LocalGenerator->EscapeForShell(di->c_str(), true);
|
||||
|
||||
// Escape this flag for the IDE.
|
||||
define = cmLocalVisualStudio7GeneratorEscapeForXML(define.c_str());
|
||||
|
||||
// Write this flag. Quote it if the definition is not
|
||||
// alphanumeric.
|
||||
if(define.find_first_not_of(
|
||||
"-_abcdefghigklmnopqrstuvwxyz1234567890ABCDEFGHIGKLMNOPQRSTUVWXYZ")
|
||||
!= define.npos)
|
||||
{
|
||||
fout << comma << """ << define << """;
|
||||
}
|
||||
else
|
||||
{
|
||||
fout << comma << define;
|
||||
}
|
||||
// Store the flag in the project file.
|
||||
fout << comma << define;
|
||||
comma = ",";
|
||||
}
|
||||
fout << "\"" << suffix;
|
||||
|
|
|
@ -26,6 +26,7 @@ class cmSourceGroup;
|
|||
struct cmVS7FlagTable;
|
||||
|
||||
class cmLocalVisualStudio7GeneratorOptions;
|
||||
class cmLocalVisualStudio7GeneratorFCInfo;
|
||||
|
||||
/** \class cmLocalVisualStudio7Generator
|
||||
* \brief Write Visual Studio .NET project files.
|
||||
|
@ -68,6 +69,7 @@ public:
|
|||
{ this->ExtraFlagTable = table; }
|
||||
private:
|
||||
typedef cmLocalVisualStudio7GeneratorOptions Options;
|
||||
typedef cmLocalVisualStudio7GeneratorFCInfo FCInfo;
|
||||
void ReadAndStoreExternalGUID(const char* name,
|
||||
const char* path);
|
||||
std::string GetBuildTypeLinkerFlags(std::string rootLinkerFlags,
|
||||
|
@ -109,7 +111,7 @@ private:
|
|||
void WriteCustomRule(std::ostream& fout,
|
||||
const char* source,
|
||||
const cmCustomCommand& command,
|
||||
const char* extraFlags);
|
||||
FCInfo& fcinfo);
|
||||
void WriteTargetVersionAttribute(std::ostream& fout, cmTarget& target);
|
||||
|
||||
void WriteGroup(const cmSourceGroup *sg,
|
||||
|
@ -117,6 +119,8 @@ private:
|
|||
const char *libName, std::vector<std::string> *configs);
|
||||
virtual std::string GetTargetDirectory(cmTarget const&) const;
|
||||
|
||||
friend class cmLocalVisualStudio7GeneratorFCInfo;
|
||||
|
||||
cmVS7FlagTable const* ExtraFlagTable;
|
||||
std::string ModuleDefinitionFile;
|
||||
int Version;
|
||||
|
|
|
@ -254,6 +254,7 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
|
|||
{
|
||||
const char *lang = l->c_str();
|
||||
std::string flags;
|
||||
std::string defines;
|
||||
bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) ||
|
||||
(this->Target->GetType() == cmTarget::MODULE_LIBRARY));
|
||||
|
||||
|
@ -264,6 +265,15 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
|
|||
flags += exportMacro;
|
||||
}
|
||||
|
||||
// Add preprocessor definitions for this target and configuration.
|
||||
this->LocalGenerator->AppendDefines
|
||||
(defines, this->Target->GetProperty("COMPILE_DEFINITIONS"));
|
||||
std::string defPropName =
|
||||
cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName);
|
||||
defPropName += "_COMPILE_DEFINITIONS";
|
||||
this->LocalGenerator->AppendDefines
|
||||
(defines, this->Target->GetProperty(defPropName.c_str()));
|
||||
|
||||
// Add language-specific flags.
|
||||
this->LocalGenerator
|
||||
->AddLanguageFlags(flags, lang,
|
||||
|
@ -286,6 +296,7 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
|
|||
AppendFlags(flags,this->GetFrameworkFlags().c_str());
|
||||
|
||||
*this->FlagFileStream << lang << "_FLAGS = " << flags << "\n\n";
|
||||
*this->FlagFileStream << lang << "_DEFINES = " << defines << "\n\n";
|
||||
}
|
||||
|
||||
// Add target-specific flags.
|
||||
|
@ -437,6 +448,35 @@ cmMakefileTargetGenerator
|
|||
<< "\n";
|
||||
}
|
||||
|
||||
// Add language-specific defines.
|
||||
std::string defines = "$(";
|
||||
defines += lang;
|
||||
defines += "_DEFINES)";
|
||||
|
||||
// Add source-sepcific preprocessor definitions.
|
||||
if(const char* compile_defs = source.GetProperty("COMPILE_DEFINITIONS"))
|
||||
{
|
||||
this->LocalGenerator->AppendDefines(defines, compile_defs);
|
||||
*this->FlagFileStream << "# Custom defines: "
|
||||
<< relativeObj << "_DEFINES = "
|
||||
<< compile_defs << "\n"
|
||||
<< "\n";
|
||||
}
|
||||
std::string configUpper =
|
||||
cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName);
|
||||
std::string defPropName = configUpper;
|
||||
defPropName += "_COMPILE_DEFINITIONS";
|
||||
if(const char* config_compile_defs =
|
||||
source.GetProperty(defPropName.c_str()))
|
||||
{
|
||||
this->LocalGenerator->AppendDefines(defines, config_compile_defs);
|
||||
*this->FlagFileStream
|
||||
<< "# Custom defines: "
|
||||
<< relativeObj << "_DEFINES_" << configUpper
|
||||
<< " = " << config_compile_defs << "\n"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
// Get the output paths for source and object files.
|
||||
std::string sourceFile = source.GetFullPath();
|
||||
if(this->LocalGenerator->UseRelativePaths)
|
||||
|
@ -522,6 +562,7 @@ cmMakefileTargetGenerator
|
|||
std::string objectDir = cmSystemTools::GetFilenamePath(obj);
|
||||
vars.ObjectDir = objectDir.c_str();
|
||||
vars.Flags = flags.c_str();
|
||||
vars.Defines = defines.c_str();
|
||||
|
||||
// Expand placeholders in the commands.
|
||||
for(std::vector<std::string>::iterator i = commands.begin();
|
||||
|
@ -601,7 +642,11 @@ cmMakefileTargetGenerator
|
|||
preprocessCommands.begin(),
|
||||
preprocessCommands.end());
|
||||
|
||||
vars.PreprocessedSource = objI.c_str();
|
||||
std::string shellObjI =
|
||||
this->Convert(objI.c_str(),
|
||||
cmLocalGenerator::NONE,
|
||||
cmLocalGenerator::SHELL).c_str();
|
||||
vars.PreprocessedSource = shellObjI.c_str();
|
||||
|
||||
// Expand placeholders in the commands.
|
||||
for(std::vector<std::string>::iterator i = commands.begin();
|
||||
|
@ -653,7 +698,11 @@ cmMakefileTargetGenerator
|
|||
assemblyCommands.begin(),
|
||||
assemblyCommands.end());
|
||||
|
||||
vars.AssemblySource = objS.c_str();
|
||||
std::string shellObjS =
|
||||
this->Convert(objS.c_str(),
|
||||
cmLocalGenerator::NONE,
|
||||
cmLocalGenerator::SHELL).c_str();
|
||||
vars.AssemblySource = shellObjS.c_str();
|
||||
|
||||
// Expand placeholders in the commands.
|
||||
for(std::vector<std::string>::iterator i = commands.begin();
|
||||
|
|
|
@ -340,7 +340,33 @@ void cmSourceFile::DefineProperties(cmake *cm)
|
|||
("COMPILE_FLAGS", cmProperty::SOURCE_FILE,
|
||||
"Additional flags to be added when compiling this source file.",
|
||||
"These flags will be added to the list of compile flags when "
|
||||
"this source file.");
|
||||
"this source file builds. Use COMPILE_DEFINITIONS to pass additional "
|
||||
"preprocessor definitions.");
|
||||
|
||||
cm->DefineProperty
|
||||
("COMPILE_DEFINITIONS", cmProperty::SOURCE_FILE,
|
||||
"Preprocessor definitions for compiling this source file.",
|
||||
"The COMPILE_DEFINITIONS property may be set to a list of preprocessor "
|
||||
"definitions using the syntax VAR or VAR=value. Function-style "
|
||||
"definitions are not supported. CMake will automatically escape "
|
||||
"the value correctly for the native build system (note that CMake "
|
||||
"language syntax may require escapes to specify some values). "
|
||||
"This property may be set on a per-configuration basis using the name "
|
||||
"<CONFIG>_COMPILE_DEFINITIONS where <CONFIG> is an upper-case name "
|
||||
"(ex. \"DEBUG_COMPILE_DEFINITIONS\").\n"
|
||||
"CMake will automatically drop some definitions that "
|
||||
"are not supported by the native build tool. "
|
||||
"The VS6 IDE does not support definitions with values "
|
||||
"(but NMake does). Xcode does not support per-configuration "
|
||||
"definitions on source files.\n"
|
||||
"Dislaimer: Most native build tools have poor support for escaping "
|
||||
"certain values. CMake has work-arounds for many cases but some "
|
||||
"values may just not be possible to pass correctly. If a value "
|
||||
"does not seem to be escaped correctly, do not attempt to "
|
||||
"work-around the problem by adding escape sequences to the value. "
|
||||
"Your work-around may break in a future version of CMake that "
|
||||
"has improved escape support. Instead consider defining the macro "
|
||||
"in a (configured) header file. Then report the limitation.");
|
||||
|
||||
cm->DefineProperty
|
||||
("EXTERNAL_OBJECT", cmProperty::SOURCE_FILE,
|
||||
|
|
|
@ -67,8 +67,32 @@ void cmTarget::DefineProperties(cmake *cm)
|
|||
("COMPILE_FLAGS", cmProperty::TARGET,
|
||||
"Additional flags to use when compiling this target's sources.",
|
||||
"The COMPILE_FLAGS property sets additional compiler flags used "
|
||||
"to build sources within the target. It may also be used to pass "
|
||||
"additional preprocessor definitions.");
|
||||
"to build sources within the target. Use COMPILE_DEFINITIONS "
|
||||
"to pass additional preprocessor definitions.");
|
||||
|
||||
cm->DefineProperty
|
||||
("COMPILE_DEFINITIONS", cmProperty::TARGET,
|
||||
"Preprocessor definitions for compiling this target's sources.",
|
||||
"The COMPILE_DEFINITIONS property may be set to a list of preprocessor "
|
||||
"definitions using the syntax VAR or VAR=value. Function-style "
|
||||
"definitions are not supported. CMake will automatically escape "
|
||||
"the value correctly for the native build system (note that CMake "
|
||||
"language syntax may require escapes to specify some values). "
|
||||
"This property may be set on a per-configuration basis using the name "
|
||||
"<CONFIG>_COMPILE_DEFINITIONS where <CONFIG> is an upper-case name "
|
||||
"(ex. \"DEBUG_COMPILE_DEFINITIONS\").\n"
|
||||
"CMake will automatically drop some definitions that "
|
||||
"are not supported by the native build tool. "
|
||||
"The VS6 IDE does not support definitions with values "
|
||||
"(but NMake does).\n"
|
||||
"Dislaimer: Most native build tools have poor support for escaping "
|
||||
"certain values. CMake has work-arounds for many cases but some "
|
||||
"values may just not be possible to pass correctly. If a value "
|
||||
"does not seem to be escaped correctly, do not attempt to "
|
||||
"work-around the problem by adding escape sequences to the value. "
|
||||
"Your work-around may break in a future version of CMake that "
|
||||
"has improved escape support. Instead consider defining the macro "
|
||||
"in a (configured) header file. Then report the limitation.");
|
||||
|
||||
cm->DefineProperty
|
||||
("DEFINE_SYMBOL", cmProperty::TARGET,
|
||||
|
|
|
@ -49,6 +49,7 @@ IF(BUILD_TESTING)
|
|||
ADD_TEST_MACRO(Properties Properties)
|
||||
ADD_TEST_MACRO(Assembler HelloAsm)
|
||||
ADD_TEST_MACRO(SourceGroups SourceGroups)
|
||||
ADD_TEST_MACRO(Preprocess Preprocess)
|
||||
|
||||
IF (CMAKE_STRICT)
|
||||
ADD_TEST_MACRO(DocTest DocTest)
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
project(Preprocess)
|
||||
|
||||
# This test is meant both as a test and as a reference for supported
|
||||
# syntax on native tool command lines.
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Construct a C-string literal to test passing through a definition on
|
||||
# the command line. We configure the value into a header so it can be
|
||||
# checked in the executable at runtime. The semicolon is handled
|
||||
# specially because it needs to be escaped in the COMPILE_DEFINITIONS
|
||||
# property value to avoid separating definitions but the string value
|
||||
# must not have it escaped inside the configured header.
|
||||
set(STRING_EXTRA "")
|
||||
|
||||
if("${CMAKE_GENERATOR}" MATCHES "Make" AND MSVC)
|
||||
set(NMAKE 1)
|
||||
endif("${CMAKE_GENERATOR}" MATCHES "Make" AND MSVC)
|
||||
|
||||
if(NOT BORLAND)
|
||||
# Borland: ;
|
||||
# The Borland compiler will simply not accept a non-escaped semicolon
|
||||
# on the command line. If it is escaped \; then the escape character
|
||||
# shows up in the preprocessing output too.
|
||||
set(SEMICOLON "\;")
|
||||
endif(NOT BORLAND)
|
||||
|
||||
if(NOT BORLAND AND NOT WATCOM)
|
||||
# Borland, WMake: multiple spaces
|
||||
# The make tool seems to remove extra whitespace from inside
|
||||
# quoted strings when passing to the compiler. It does not have
|
||||
# trouble passing to other tools, and the compiler may be directly
|
||||
# invoked from the command line.
|
||||
set(STRING_EXTRA "${STRING_EXTRA} ")
|
||||
endif(NOT BORLAND AND NOT WATCOM)
|
||||
|
||||
if(NOT "${CMAKE_GENERATOR}" MATCHES "Visual Studio")
|
||||
# VS: ,
|
||||
# Visual Studio will not accept a comma in the value of a definition.
|
||||
# The comma-separated list of PreprocessorDefinitions in the project
|
||||
# file seems to be parsed before the content of entries is examined.
|
||||
set(STRING_EXTRA "${STRING_EXTRA},")
|
||||
endif(NOT "${CMAKE_GENERATOR}" MATCHES "Visual Studio")
|
||||
|
||||
if(NOT MINGW)
|
||||
# MinGW: &
|
||||
# When inside -D"FOO=\"a & b\"" MinGW make wants -D"FOO=\"a "&" b\""
|
||||
# but it does not like quoted ampersand elsewhere.
|
||||
set(STRING_EXTRA "${STRING_EXTRA}&")
|
||||
endif(NOT MINGW)
|
||||
|
||||
if(NOT MINGW)
|
||||
# MinGW: |
|
||||
# When inside -D"FOO=\"a | b\"" MinGW make wants -D"FOO=\"a "|" b\""
|
||||
# but it does not like quoted pipe elsewhere.
|
||||
set(STRING_EXTRA "${STRING_EXTRA}|")
|
||||
endif(NOT MINGW)
|
||||
|
||||
if(NOT BORLAND AND NOT MINGW AND NOT NMAKE)
|
||||
# Borland, NMake, MinGW: ^
|
||||
# When inside -D"FOO=\"a ^ b\"" they make wants -D"FOO=\"a "^" b\""
|
||||
# but do not like quoted carrot elsewhere. In NMake the non-quoted
|
||||
# syntax works when the flags are not in a make variable.
|
||||
set(STRING_EXTRA "${STRING_EXTRA}^")
|
||||
endif(NOT BORLAND AND NOT MINGW AND NOT NMAKE)
|
||||
|
||||
if(NOT BORLAND AND NOT MINGW AND NOT NMAKE)
|
||||
# Borland, MinGW: < >
|
||||
# Angle-brackets have funny behavior that is hard to escape.
|
||||
set(STRING_EXTRA "${STRING_EXTRA}<>")
|
||||
endif(NOT BORLAND AND NOT MINGW AND NOT NMAKE)
|
||||
|
||||
# General: \"
|
||||
# Make tools do not reliably accept \\\" syntax:
|
||||
# - MinGW and MSYS make tools crash with \\\"
|
||||
# - Borland make actually wants a mis-matched quote \\"
|
||||
# or $(BACKSLASH)\" where BACKSLASH is a variable set to \\
|
||||
# - VS IDE gets confused about the bounds of the definition value \\\"
|
||||
# - NMake is okay with just \\\"
|
||||
if(NMAKE OR "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles")
|
||||
set(STRING_EXTRA "${STRING_EXTRA}\\\"")
|
||||
endif(NMAKE OR "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles")
|
||||
|
||||
# General: #
|
||||
# MSVC will not accept a # in the value of a string definition on the
|
||||
# command line. The character seems to be simply replaced by an
|
||||
# equals =. According to "cl -help" definitions may be specified by
|
||||
# -DMACRO#VALUE as well as -DMACRO=VALUE. It must be implemented by a
|
||||
# simple search-and-replace.
|
||||
#
|
||||
# The Borland compiler will parse both # and \# as just # but the make
|
||||
# tool seems to want \# sometimes and not others.
|
||||
#
|
||||
# Unix make does not like # in variable settings without extra
|
||||
# escaping. This could probably be fixed but since MSVC does not
|
||||
# support it and it is not an operator it is not worthwhile.
|
||||
|
||||
# Compose the final test string.
|
||||
set(STRING_VALUE "hello `~!@$%*)(_+-=}{][:'.?/ ${STRING_EXTRA}world")
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Function-style macro command-line support:
|
||||
# - Borland does not support
|
||||
# - MSVC does not support
|
||||
# - Watcom does not support
|
||||
# - GCC supports
|
||||
|
||||
# Too few platforms support this to bother implementing.
|
||||
# People can just configure headers with the macros.
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Construct a sample expression to pass as a macro definition.
|
||||
|
||||
set(EXPR "x*y+!(x==(y+1*2))*f(x%2)")
|
||||
|
||||
if(NOT WATCOM)
|
||||
# Watcom does not support - or / because it parses them as options.
|
||||
set(EXPR "${EXPR}+y/x-x")
|
||||
endif(NOT WATCOM)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Inform the test if the debug configuration is getting built.
|
||||
# The NDEBUG definition takes care of this for release.
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DPREPROCESS_DEBUG")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DPREPROCESS_DEBUG")
|
||||
|
||||
# Inform the test if it built from Xcode or VS6 IDE.
|
||||
if(XCODE)
|
||||
set(PREPROCESS_XCODE 1)
|
||||
endif(XCODE)
|
||||
if("${CMAKE_GENERATOR}" MATCHES "Visual Studio 6")
|
||||
set(PREPROCESS_VS6 1)
|
||||
set(VS6 _vs6)
|
||||
endif("${CMAKE_GENERATOR}" MATCHES "Visual Studio 6")
|
||||
|
||||
# Test old-style definitions.
|
||||
add_definitions(-DOLD_DEF -DOLD_EXPR=2)
|
||||
|
||||
set(FILE_PATH "${Preprocess_SOURCE_DIR}/file_def.h")
|
||||
set(TARGET_PATH "${Preprocess_SOURCE_DIR}/target_def.h")
|
||||
|
||||
# Create a list of definition property strings.
|
||||
set(TARGET_DEFS "TARGET_DEF")
|
||||
set(FILE_DEFS "FILE_DEF")
|
||||
|
||||
# Add definitions with values. VS6 does not support this.
|
||||
if(NOT PREPROCESS_VS6)
|
||||
list(APPEND TARGET_DEFS
|
||||
"TARGET_STRING=\"${STRING_VALUE}${SEMICOLON}\""
|
||||
"TARGET_EXPR=${EXPR}"
|
||||
"TARGET_PATH=\"${TARGET_PATH}\""
|
||||
)
|
||||
list(APPEND FILE_DEFS
|
||||
"FILE_STRING=\"${STRING_VALUE}${SEMICOLON}\""
|
||||
"FILE_EXPR=${EXPR}"
|
||||
"FILE_PATH=\"${FILE_PATH}\""
|
||||
)
|
||||
endif(NOT PREPROCESS_VS6)
|
||||
|
||||
add_executable(Preprocess preprocess.c preprocess${VS6}.cxx)
|
||||
set_target_properties(Preprocess PROPERTIES
|
||||
COMPILE_DEFINITIONS "${TARGET_DEFS}"
|
||||
DEBUG_COMPILE_DEFINITIONS "TARGET_DEF_DEBUG"
|
||||
RELEASE_COMPILE_DEFINITIONS "TARGET_DEF_RELEASE"
|
||||
)
|
||||
set_source_files_properties(preprocess.c preprocess${VS6}.cxx PROPERTIES
|
||||
COMPILE_DEFINITIONS "${FILE_DEFS}"
|
||||
DEBUG_COMPILE_DEFINITIONS "FILE_DEF_DEBUG"
|
||||
RELEASE_COMPILE_DEFINITIONS "FILE_DEF_RELEASE"
|
||||
)
|
||||
|
||||
# Helper target for running test manually in build tree.
|
||||
add_custom_target(drive COMMAND Preprocess)
|
||||
|
||||
# Configure the header file with the desired string value.
|
||||
if(SEMICOLON)
|
||||
set(STRING_VALUE "${STRING_VALUE};")
|
||||
endif(SEMICOLON)
|
||||
configure_file(${Preprocess_SOURCE_DIR}/preprocess.h.in
|
||||
${Preprocess_BINARY_DIR}/preprocess.h)
|
||||
include_directories(${Preprocess_BINARY_DIR})
|
|
@ -0,0 +1 @@
|
|||
#define FILE_PATH_DEF
|
|
@ -0,0 +1,170 @@
|
|||
#include <preprocess.h>
|
||||
|
||||
#include FILE_PATH
|
||||
#include TARGET_PATH
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int check_defines_C(void)
|
||||
{
|
||||
int result = 1;
|
||||
#ifndef PREPROCESS_VS6
|
||||
if(strcmp(FILE_STRING, STRING_VALUE) != 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"FILE_STRING has wrong value in C [%s]\n", FILE_STRING);
|
||||
result = 0;
|
||||
}
|
||||
if(strcmp(TARGET_STRING, STRING_VALUE) != 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"TARGET_STRING has wrong value in C [%s]\n", TARGET_STRING);
|
||||
result = 0;
|
||||
}
|
||||
{
|
||||
int x = 2;
|
||||
int y = 3;
|
||||
if((FILE_EXPR) != (EXPR))
|
||||
{
|
||||
fprintf(stderr, "FILE_EXPR did not work in C [%s]\n",
|
||||
TO_STRING(FILE_EXPR));
|
||||
result = 0;
|
||||
}
|
||||
if((TARGET_EXPR) != (EXPR))
|
||||
{
|
||||
fprintf(stderr, "TARGET_EXPR did not work in C [%s]\n",
|
||||
TO_STRING(FILE_EXPR));
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef NDEBUG
|
||||
# ifdef FILE_DEF_DEBUG
|
||||
{
|
||||
fprintf(stderr, "FILE_DEF_DEBUG should not be defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# ifdef TARGET_DEF_DEBUG
|
||||
{
|
||||
fprintf(stderr, "TARGET_DEF_DEBUG should not be defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# ifndef FILE_DEF_RELEASE
|
||||
# ifndef PREPROCESS_XCODE
|
||||
{
|
||||
fprintf(stderr, "FILE_DEF_RELEASE should be defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# ifndef TARGET_DEF_RELEASE
|
||||
{
|
||||
fprintf(stderr, "TARGET_DEF_RELEASE should be defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#ifdef PREPROCESS_DEBUG
|
||||
# ifndef FILE_DEF_DEBUG
|
||||
# ifndef PREPROCESS_XCODE
|
||||
{
|
||||
fprintf(stderr, "FILE_DEF_DEBUG should be defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# ifndef TARGET_DEF_DEBUG
|
||||
{
|
||||
fprintf(stderr, "TARGET_DEF_DEBUG should be defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# ifdef FILE_DEF_RELEASE
|
||||
{
|
||||
fprintf(stderr, "FILE_DEF_RELEASE should not be defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# ifdef TARGET_DEF_RELEASE
|
||||
{
|
||||
fprintf(stderr, "TARGET_DEF_RELEASE should not be defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#if defined(FILE_DEF_DEBUG) || defined(TARGET_DEF_DEBUG)
|
||||
# if !defined(FILE_DEF_DEBUG) || !defined(TARGET_DEF_DEBUG)
|
||||
# ifndef PREPROCESS_XCODE
|
||||
{
|
||||
fprintf(stderr,
|
||||
"FILE_DEF_DEBUG and TARGET_DEF_DEBUG inconsistent in C\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# if defined(FILE_DEF_RELEASE) || defined(TARGET_DEF_RELEASE)
|
||||
{
|
||||
fprintf(stderr, "DEBUG and RELEASE definitions inconsistent in C\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#if defined(FILE_DEF_RELEASE) || defined(TARGET_DEF_RELEASE)
|
||||
# if !defined(FILE_DEF_RELEASE) || !defined(TARGET_DEF_RELEASE)
|
||||
# ifndef PREPROCESS_XCODE
|
||||
{
|
||||
fprintf(stderr,
|
||||
"FILE_DEF_RELEASE and TARGET_DEF_RELEASE inconsistent in C\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# if defined(FILE_DEF_DEBUG) || defined(TARGET_DEF_DEBUG)
|
||||
{
|
||||
fprintf(stderr, "RELEASE and DEBUG definitions inconsistent in C\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#ifndef FILE_PATH_DEF
|
||||
{
|
||||
fprintf(stderr, "FILE_PATH_DEF not defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
#ifndef TARGET_PATH_DEF
|
||||
{
|
||||
fprintf(stderr, "TARGET_PATH_DEF not defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
#ifndef FILE_DEF
|
||||
{
|
||||
fprintf(stderr, "FILE_DEF not defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
#ifndef TARGET_DEF
|
||||
{
|
||||
fprintf(stderr, "TARGET_DEF not defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
#ifndef OLD_DEF
|
||||
{
|
||||
fprintf(stderr, "OLD_DEF not defined in C\n");
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
#if !defined(OLD_EXPR) || OLD_EXPR != 2
|
||||
{
|
||||
fprintf(stderr, "OLD_EXPR id not work in C [%s]\n",
|
||||
TO_STRING(OLD_EXPR));
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
#include <preprocess.h>
|
||||
|
||||
#include FILE_PATH
|
||||
#include TARGET_PATH
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" int check_defines_C(void);
|
||||
|
||||
int check_defines_CXX()
|
||||
{
|
||||
int result = 1;
|
||||
#ifndef PREPROCESS_VS6
|
||||
if(strcmp(FILE_STRING, STRING_VALUE) != 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"FILE_STRING has wrong value in CXX [%s]\n", FILE_STRING);
|
||||
result = 0;
|
||||
}
|
||||
if(strcmp(TARGET_STRING, STRING_VALUE) != 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"TARGET_STRING has wrong value in CXX [%s]\n", TARGET_STRING);
|
||||
result = 0;
|
||||
}
|
||||
{
|
||||
int x = 2;
|
||||
int y = 3;
|
||||
if((FILE_EXPR) != (EXPR))
|
||||
{
|
||||
fprintf(stderr, "FILE_EXPR did not work in CXX [%s]\n",
|
||||
TO_STRING(FILE_EXPR));
|
||||
result = 0;
|
||||
}
|
||||
if((TARGET_EXPR) != (EXPR))
|
||||
{
|
||||
fprintf(stderr, "TARGET_EXPR did not work in CXX [%s]\n",
|
||||
TO_STRING(FILE_EXPR));
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef NDEBUG
|
||||
# ifdef FILE_DEF_DEBUG
|
||||
{
|
||||
fprintf(stderr, "FILE_DEF_DEBUG should not be defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# ifdef TARGET_DEF_DEBUG
|
||||
{
|
||||
fprintf(stderr, "TARGET_DEF_DEBUG should not be defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# ifndef FILE_DEF_RELEASE
|
||||
# ifndef PREPROCESS_XCODE
|
||||
{
|
||||
fprintf(stderr, "FILE_DEF_RELEASE should be defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# ifndef TARGET_DEF_RELEASE
|
||||
{
|
||||
fprintf(stderr, "TARGET_DEF_RELEASE should be defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#ifdef PREPROCESS_DEBUG
|
||||
# ifndef FILE_DEF_DEBUG
|
||||
# ifndef PREPROCESS_XCODE
|
||||
{
|
||||
fprintf(stderr, "FILE_DEF_DEBUG should be defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# ifndef TARGET_DEF_DEBUG
|
||||
{
|
||||
fprintf(stderr, "TARGET_DEF_DEBUG should be defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# ifdef FILE_DEF_RELEASE
|
||||
{
|
||||
fprintf(stderr, "FILE_DEF_RELEASE should not be defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# ifdef TARGET_DEF_RELEASE
|
||||
{
|
||||
fprintf(stderr, "TARGET_DEF_RELEASE should not be defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#if defined(FILE_DEF_DEBUG) || defined(TARGET_DEF_DEBUG)
|
||||
# if !defined(FILE_DEF_DEBUG) || !defined(TARGET_DEF_DEBUG)
|
||||
# ifndef PREPROCESS_XCODE
|
||||
{
|
||||
fprintf(stderr,
|
||||
"FILE_DEF_DEBUG and TARGET_DEF_DEBUG inconsistent in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# if defined(FILE_DEF_RELEASE) || defined(TARGET_DEF_RELEASE)
|
||||
{
|
||||
fprintf(stderr, "DEBUG and RELEASE definitions inconsistent in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#if defined(FILE_DEF_RELEASE) || defined(TARGET_DEF_RELEASE)
|
||||
# if !defined(FILE_DEF_RELEASE) || !defined(TARGET_DEF_RELEASE)
|
||||
# ifndef PREPROCESS_XCODE
|
||||
{
|
||||
fprintf(stderr,
|
||||
"FILE_DEF_RELEASE and TARGET_DEF_RELEASE inconsistent in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
# if defined(FILE_DEF_DEBUG) || defined(TARGET_DEF_DEBUG)
|
||||
{
|
||||
fprintf(stderr, "RELEASE and DEBUG definitions inconsistent in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#ifndef FILE_PATH_DEF
|
||||
{
|
||||
fprintf(stderr, "FILE_PATH_DEF not defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
#ifndef TARGET_PATH_DEF
|
||||
{
|
||||
fprintf(stderr, "TARGET_PATH_DEF not defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
#ifndef FILE_DEF
|
||||
{
|
||||
fprintf(stderr, "FILE_DEF not defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
#ifndef TARGET_DEF
|
||||
{
|
||||
fprintf(stderr, "TARGET_DEF not defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
#ifndef OLD_DEF
|
||||
{
|
||||
fprintf(stderr, "OLD_DEF not defined in CXX\n");
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
#if !defined(OLD_EXPR) || OLD_EXPR != 2
|
||||
{
|
||||
fprintf(stderr, "OLD_EXPR id not work in C [%s]\n",
|
||||
TO_STRING(OLD_EXPR));
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int result = 1;
|
||||
|
||||
if(!check_defines_C())
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
|
||||
if(!check_defines_CXX())
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
|
||||
if(result)
|
||||
{
|
||||
printf("All preprocessor definitions are correct.\n");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/* Define configured macros. */
|
||||
#define STRING_VALUE "@STRING_VALUE@"
|
||||
#define EXPR @EXPR@
|
||||
#cmakedefine PREPROCESS_XCODE
|
||||
#cmakedefine PREPROCESS_VS6
|
||||
|
||||
#ifdef PREPROCESS_VS6
|
||||
# define FILE_PATH "@FILE_PATH@"
|
||||
# define TARGET_PATH "@TARGET_PATH@"
|
||||
#endif
|
||||
|
||||
/* Declarations and macros shared by all sources. */
|
||||
#define TO_STRING(x) TO_STRING0(x)
|
||||
#define TO_STRING0(x) #x
|
||||
|
||||
static int f(int i) { return i*3; }
|
|
@ -0,0 +1,3 @@
|
|||
// The VS6 IDE does not support object name configuration so we need a
|
||||
// source file with a different name. Include the real source file.
|
||||
#include "preprocess.cxx"
|
|
@ -0,0 +1 @@
|
|||
#define TARGET_PATH_DEF
|
Loading…
Reference in New Issue