Merge topic 'object-library'

93d5509 Merge branch 'ninja-object-library' into object-library
821037c Merge branch 'xcode-object-library' into object-library
eb24c99 Merge branch 'object-library' into xcode-object-library
63d1be8 Xcode: Honor $<TARGET_OBJECTS:...> source expressions
020ba38 Merge branch 'object-library' into xcode-object-library
e8ea615 Build object library targets in Xcode
8045e17 Pre-compute object file names before Xcode generation
247a132 Allow txt files as ExtraSources in object library targets
b063599 Add a default source group for object files.
be01f3b Xcode: Re-factor some existing methods into "FromPath" variants
2693dbe Merge branch 'object-library' into ninja-object-library
51997cb Ninja: Honor $<TARGET_OBJECTS:...> source expressions
23ec258 Merge branch 'object-library' into ninja-object-library
61124de Build object library targets in Ninja
f5b06cd Pre-compute object file names before Ninja generation
a2514f1 Simplify cmNinjaTargetGenerator using cmGeneratorTarget
...
This commit is contained in:
David Cole 2012-03-20 09:34:35 -04:00 committed by CMake Topic Stage
commit 31c0bc0219
121 changed files with 1703 additions and 479 deletions

View File

@ -185,6 +185,8 @@ SET(SRCS
cmGeneratedFileStream.cxx
cmGeneratorExpression.cxx
cmGeneratorExpression.h
cmGeneratorTarget.cxx
cmGeneratorTarget.h
cmGlobalGenerator.cxx
cmGlobalGenerator.h
cmGlobalUnixMakefileGenerator3.cxx

View File

@ -64,6 +64,12 @@ bool cmAddLibraryCommand
type = cmTarget::MODULE_LIBRARY;
haveSpecifiedType = true;
}
else if(libType == "OBJECT")
{
++s;
type = cmTarget::OBJECT_LIBRARY;
haveSpecifiedType = true;
}
else if(libType == "UNKNOWN")
{
++s;
@ -118,6 +124,14 @@ bool cmAddLibraryCommand
this->SetError("called with IMPORTED argument but no library type.");
return false;
}
if(type == cmTarget::OBJECT_LIBRARY)
{
this->Makefile->IssueMessage(
cmake::FATAL_ERROR,
"The OBJECT library type may not be used for IMPORTED libraries."
);
return true;
}
// Make sure the target does not already exist.
if(this->Makefile->FindTargetToUse(libName.c_str()))

View File

@ -112,6 +112,26 @@ public:
"(and its per-configuration version IMPORTED_LOCATION_<CONFIG>) "
"which specifies the location of the main library file on disk. "
"See documentation of the IMPORTED_* properties for more information."
"\n"
"The signature\n"
" add_library(<name> OBJECT <src>...)\n"
"creates a special \"object library\" target. "
"An object library compiles source files but does not archive or link "
"their object files into a library. "
"Instead other targets created by add_library or add_executable may "
"reference the objects using an expression of the form "
"$<TARGET_OBJECTS:objlib> as a source, where \"objlib\" is the "
"object library name. "
"For example:\n"
" add_library(... $<TARGET_OBJECTS:objlib> ...)\n"
" add_executable(... $<TARGET_OBJECTS:objlib> ...)\n"
"will include objlib's object files in a library and an executable "
"along with those compiled from their own sources. "
"Object libraries may contain only sources (and headers) that compile "
"to object files. "
"They may contain custom commands generating such sources, but not "
"PRE_BUILD, PRE_LINK, or POST_BUILD commands. "
"Object libraries cannot be imported, exported, installed, or linked."
;
}

View File

@ -633,6 +633,19 @@ cmTarget* cmComputeLinkDepends::FindTargetToLink(int depender_index,
tgt = 0;
}
if(tgt && tgt->GetType() == cmTarget::OBJECT_LIBRARY)
{
cmOStringStream e;
e << "Target \"" << this->Target->GetName() << "\" links to "
"OBJECT library \"" << tgt->GetName() << "\" but this is not "
"allowed. "
"One may link only to STATIC or SHARED libraries, or to executables "
"with the ENABLE_EXPORTS property set.";
this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR, e.str(),
this->Target->GetBacktrace());
tgt = 0;
}
// Return the target found, if any.
return tgt;
}

View File

@ -124,6 +124,14 @@ bool cmExportCommand
{
targets.push_back(target);
}
else if(target->GetType() == cmTarget::OBJECT_LIBRARY)
{
cmOStringStream e;
e << "given OBJECT library \"" << *currentTarget
<< "\" which may not be exported.";
this->SetError(e.str().c_str());
return false;
}
else
{
cmOStringStream e;

View File

@ -0,0 +1,172 @@
/*============================================================================
CMake - Cross Platform Makefile Generator
Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#include "cmGeneratorTarget.h"
#include "cmTarget.h"
#include "cmMakefile.h"
#include "cmLocalGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmSourceFile.h"
//----------------------------------------------------------------------------
cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t)
{
this->Makefile = this->Target->GetMakefile();
this->LocalGenerator = this->Makefile->GetLocalGenerator();
this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
this->ClassifySources();
this->LookupObjectLibraries();
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::ClassifySources()
{
bool isObjLib = this->Target->GetType() == cmTarget::OBJECT_LIBRARY;
std::vector<cmSourceFile*> badObjLib;
std::vector<cmSourceFile*> const& sources = this->Target->GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator si = sources.begin();
si != sources.end(); ++si)
{
cmSourceFile* sf = *si;
cmTarget::SourceFileFlags tsFlags =
this->Target->GetTargetSourceFileFlags(sf);
if(sf->GetCustomCommand())
{
this->CustomCommands.push_back(sf);
}
else if(tsFlags.Type != cmTarget::SourceFileTypeNormal)
{
this->OSXContent.push_back(sf);
if(isObjLib) { badObjLib.push_back(sf); }
}
else if(sf->GetPropertyAsBool("HEADER_FILE_ONLY"))
{
this->HeaderSources.push_back(sf);
}
else if(sf->GetPropertyAsBool("EXTERNAL_OBJECT"))
{
this->ExternalObjects.push_back(sf);
if(isObjLib) { badObjLib.push_back(sf); }
}
else if(cmSystemTools::LowerCase(sf->GetExtension()) == "def")
{
this->ModuleDefinitionFile = sf->GetFullPath();
if(isObjLib) { badObjLib.push_back(sf); }
}
else if(this->GlobalGenerator->IgnoreFile(sf->GetExtension().c_str()))
{
// We only get here if a source file is not an external object
// and has an extension that is listed as an ignored file type.
// No message or diagnosis should be given.
}
else if(sf->GetLanguage())
{
this->ObjectSources.push_back(sf);
}
else
{
this->ExtraSources.push_back(sf);
if(isObjLib && cmSystemTools::LowerCase(sf->GetExtension()) != "txt")
{
badObjLib.push_back(sf);
}
}
}
if(!badObjLib.empty())
{
cmOStringStream e;
e << "OBJECT library \"" << this->Target->GetName() << "\" contains:\n";
for(std::vector<cmSourceFile*>::iterator i = badObjLib.begin();
i != badObjLib.end(); ++i)
{
e << " " << (*i)->GetLocation().GetName() << "\n";
}
e << "but may contain only headers and sources that compile.";
this->GlobalGenerator->GetCMakeInstance()
->IssueMessage(cmake::FATAL_ERROR, e.str(),
this->Target->GetBacktrace());
}
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::LookupObjectLibraries()
{
std::vector<std::string> const& objLibs =
this->Target->GetObjectLibraries();
for(std::vector<std::string>::const_iterator oli = objLibs.begin();
oli != objLibs.end(); ++oli)
{
std::string const& objLibName = *oli;
if(cmTarget* objLib = this->Makefile->FindTargetToUse(objLibName.c_str()))
{
if(objLib->GetType() == cmTarget::OBJECT_LIBRARY)
{
if(this->Target->GetType() != cmTarget::EXECUTABLE &&
this->Target->GetType() != cmTarget::STATIC_LIBRARY &&
this->Target->GetType() != cmTarget::SHARED_LIBRARY &&
this->Target->GetType() != cmTarget::MODULE_LIBRARY)
{
this->GlobalGenerator->GetCMakeInstance()
->IssueMessage(cmake::FATAL_ERROR,
"Only executables and non-OBJECT libraries may "
"reference target objects.",
this->Target->GetBacktrace());
return;
}
this->Target->AddUtility(objLib->GetName());
this->ObjectLibraries.push_back(objLib);
}
else
{
cmOStringStream e;
e << "Objects of target \"" << objLibName
<< "\" referenced but is not an OBJECT library.";
this->GlobalGenerator->GetCMakeInstance()
->IssueMessage(cmake::FATAL_ERROR, e.str(),
this->Target->GetBacktrace());
return;
}
}
else
{
cmOStringStream e;
e << "Objects of target \"" << objLibName
<< "\" referenced but no such target exists.";
this->GlobalGenerator->GetCMakeInstance()
->IssueMessage(cmake::FATAL_ERROR, e.str(),
this->Target->GetBacktrace());
return;
}
}
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::UseObjectLibraries(std::vector<std::string>& objs)
{
for(std::vector<cmTarget*>::const_iterator
ti = this->ObjectLibraries.begin();
ti != this->ObjectLibraries.end(); ++ti)
{
cmTarget* objLib = *ti;
cmGeneratorTarget* ogt =
this->GlobalGenerator->GetGeneratorTarget(objLib);
for(std::vector<cmSourceFile*>::const_iterator
si = ogt->ObjectSources.begin();
si != ogt->ObjectSources.end(); ++si)
{
std::string obj = ogt->ObjectDirectory;
obj += ogt->Objects[*si];
objs.push_back(obj);
}
}
}

View File

@ -0,0 +1,63 @@
/*============================================================================
CMake - Cross Platform Makefile Generator
Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#ifndef cmGeneratorTarget_h
#define cmGeneratorTarget_h
#include "cmStandardIncludes.h"
class cmCustomCommand;
class cmGlobalGenerator;
class cmLocalGenerator;
class cmMakefile;
class cmSourceFile;
class cmTarget;
class cmGeneratorTarget
{
public:
cmGeneratorTarget(cmTarget*);
cmTarget* Target;
cmMakefile* Makefile;
cmLocalGenerator* LocalGenerator;
cmGlobalGenerator* GlobalGenerator;
/** Sources classified by purpose. */
std::vector<cmSourceFile*> CustomCommands;
std::vector<cmSourceFile*> ExtraSources;
std::vector<cmSourceFile*> HeaderSources;
std::vector<cmSourceFile*> ObjectSources;
std::vector<cmSourceFile*> ExternalObjects;
std::vector<cmSourceFile*> OSXContent;
std::string ModuleDefinitionFile;
std::map<cmSourceFile const*, std::string> Objects;
std::set<cmSourceFile const*> ExplicitObjectName;
/** Full path with trailing slash to the top-level directory
holding object files for this target. Includes the build
time config name placeholder if needed for the generator. */
std::string ObjectDirectory;
std::vector<cmTarget*> ObjectLibraries;
void UseObjectLibraries(std::vector<std::string>& objs);
private:
void ClassifySources();
void LookupObjectLibraries();
cmGeneratorTarget(cmGeneratorTarget const&);
void operator=(cmGeneratorTarget const&);
};
#endif

View File

@ -24,6 +24,7 @@
#include "cmExportInstallFileGenerator.h"
#include "cmComputeTargetDepends.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include <cmsys/Directory.hxx>
@ -74,6 +75,7 @@ cmGlobalGenerator::~cmGlobalGenerator()
delete this->ExtraGenerator;
}
this->ClearGeneratorTargets();
this->ClearExportSets();
}
@ -807,6 +809,7 @@ bool cmGlobalGenerator::IsDependedOn(const char* project,
void cmGlobalGenerator::Configure()
{
this->FirstTimeProgress = 0.0f;
this->ClearGeneratorTargets();
this->ClearExportSets();
// Delete any existing cmLocalGenerators
unsigned int i;
@ -947,6 +950,9 @@ void cmGlobalGenerator::Generate()
this->LocalGenerators[i]->GenerateTargetManifest();
}
// Create per-target generator information.
this->CreateGeneratorTargets();
// Compute the inter-target dependencies.
if(!this->ComputeTargetDepends())
{
@ -1056,6 +1062,55 @@ void cmGlobalGenerator::CreateAutomocTargets()
#endif
}
//----------------------------------------------------------------------------
void cmGlobalGenerator::CreateGeneratorTargets()
{
// Construct per-target generator information.
for(unsigned int i=0; i < this->LocalGenerators.size(); ++i)
{
cmTargets& targets =
this->LocalGenerators[i]->GetMakefile()->GetTargets();
for(cmTargets::iterator ti = targets.begin();
ti != targets.end(); ++ti)
{
cmTarget* t = &ti->second;
cmGeneratorTarget* gt = new cmGeneratorTarget(t);
this->GeneratorTargets[t] = gt;
this->ComputeTargetObjects(gt);
}
}
}
//----------------------------------------------------------------------------
void cmGlobalGenerator::ClearGeneratorTargets()
{
for(GeneratorTargetsType::iterator i = this->GeneratorTargets.begin();
i != this->GeneratorTargets.end(); ++i)
{
delete i->second;
}
this->GeneratorTargets.clear();
}
//----------------------------------------------------------------------------
cmGeneratorTarget* cmGlobalGenerator::GetGeneratorTarget(cmTarget* t) const
{
GeneratorTargetsType::const_iterator ti = this->GeneratorTargets.find(t);
if(ti == this->GeneratorTargets.end())
{
this->CMakeInstance->IssueMessage(
cmake::INTERNAL_ERROR, "Missing cmGeneratorTarget instance!",
cmListFileBacktrace());
return 0;
}
return ti->second;
}
//----------------------------------------------------------------------------
void cmGlobalGenerator::ComputeTargetObjects(cmGeneratorTarget*) const
{
// Implemented in generator subclasses that need this.
}
void cmGlobalGenerator::CheckLocalGenerators()
{
@ -1714,7 +1769,7 @@ void cmGlobalGenerator::SetCMakeInstance(cmake* cm)
void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets)
{
cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
const char* cmakeCfgIntDir = this->GetCMakeCFGInitDirectory();
const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
const char* cmakeCommand = mf->GetRequiredDefinition("CMAKE_COMMAND");
// CPack

View File

@ -19,6 +19,7 @@
#include "cmTargetDepend.h" // For cmTargetDependSet
#include "cmSystemTools.h" // for cmSystemTools::OutputOption
class cmake;
class cmGeneratorTarget;
class cmMakefile;
class cmLocalGenerator;
class cmExternalMakefileProjectGenerator;
@ -183,7 +184,7 @@ public:
const char* GetLanguageOutputExtension(cmSourceFile const&);
///! What is the configurations directory variable called?
virtual const char* GetCMakeCFGInitDirectory() { return "."; }
virtual const char* GetCMakeCFGIntDir() const { return "."; }
/** Get whether the generator should use a script for link commands. */
bool GetUseLinkScript() const { return this->UseLinkScript; }
@ -251,6 +252,9 @@ public:
// via a target_link_libraries or add_dependencies
TargetDependSet const& GetTargetDirectDepends(cmTarget & target);
/** Get per-target generator information. */
cmGeneratorTarget* GetGeneratorTarget(cmTarget*) const;
const std::map<cmStdString, std::vector<cmLocalGenerator*> >& GetProjectMap()
const {return this->ProjectMap;}
@ -370,6 +374,13 @@ private:
typedef std::map<cmTarget *, TargetDependSet> TargetDependMap;
TargetDependMap TargetDependencies;
// Per-target generator information.
typedef std::map<cmTarget*, cmGeneratorTarget*> GeneratorTargetsType;
GeneratorTargetsType GeneratorTargets;
void CreateGeneratorTargets();
void ClearGeneratorTargets();
virtual void ComputeTargetObjects(cmGeneratorTarget* gt) const;
// Cache directory content and target files to be built.
struct DirectoryContent: public std::set<cmStdString>
{

View File

@ -14,6 +14,7 @@
#include "cmLocalNinjaGenerator.h"
#include "cmMakefile.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmVersion.h"
const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja";
@ -499,6 +500,34 @@ bool cmGlobalNinjaGenerator::HasRule(const std::string &name)
return (rule != this->Rules.end());
}
//----------------------------------------------------------------------------
// Private virtual overrides
// TODO: Refactor to combine with cmGlobalUnixMakefileGenerator3 impl.
void cmGlobalNinjaGenerator::ComputeTargetObjects(cmGeneratorTarget* gt) const
{
cmTarget* target = gt->Target;
// Compute full path to object file directory for this target.
std::string dir_max;
dir_max += gt->Makefile->GetCurrentOutputDirectory();
dir_max += "/";
dir_max += gt->LocalGenerator->GetTargetDirectory(*target);
dir_max += "/";
gt->ObjectDirectory = dir_max;
// Compute the name of each object file.
for(std::vector<cmSourceFile*>::iterator
si = gt->ObjectSources.begin();
si != gt->ObjectSources.end(); ++si)
{
cmSourceFile* sf = *si;
std::string objectName = gt->LocalGenerator
->GetObjectFileNameWithoutTarget(*sf, dir_max);
gt->Objects[sf] = objectName;
}
}
//----------------------------------------------------------------------------
// Private methods
@ -635,6 +664,7 @@ cmGlobalNinjaGenerator
target->GetFullPath(configName).c_str()));
break;
case cmTarget::OBJECT_LIBRARY:
case cmTarget::UTILITY: {
std::string path = ng->ConvertToNinjaPath(
target->GetMakefile()->GetStartOutputDirectory());

View File

@ -18,6 +18,7 @@
class cmLocalGenerator;
class cmGeneratedFileStream;
class cmGeneratorTarget;
/**
* \class cmGlobalNinjaGenerator
@ -235,6 +236,11 @@ protected:
/// @see cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS()
virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() { return true; }
private:
/// @see cmGlobalGenerator::ComputeTargetObjects
virtual void ComputeTargetObjects(cmGeneratorTarget* gt) const;
private:
// In order to access the AddDependencyToAll() functions and co.
friend class cmLocalNinjaGenerator;

View File

@ -17,6 +17,7 @@
#include "cmGeneratedFileStream.h"
#include "cmSourceFile.h"
#include "cmTarget.h"
#include "cmGeneratorTarget.h"
cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3()
{
@ -70,6 +71,38 @@ void cmGlobalUnixMakefileGenerator3
"default make target. A \"make install\" target is also provided.";
}
//----------------------------------------------------------------------------
void
cmGlobalUnixMakefileGenerator3
::ComputeTargetObjects(cmGeneratorTarget* gt) const
{
cmTarget* target = gt->Target;
cmLocalUnixMakefileGenerator3* lg =
static_cast<cmLocalUnixMakefileGenerator3*>(gt->LocalGenerator);
// Compute full path to object file directory for this target.
std::string dir_max;
dir_max += gt->Makefile->GetCurrentOutputDirectory();
dir_max += "/";
dir_max += gt->LocalGenerator->GetTargetDirectory(*target);
dir_max += "/";
gt->ObjectDirectory = dir_max;
// Compute the name of each object file.
for(std::vector<cmSourceFile*>::iterator
si = gt->ObjectSources.begin();
si != gt->ObjectSources.end(); ++si)
{
cmSourceFile* sf = *si;
bool hasSourceExtension = true;
std::string objectName = gt->LocalGenerator
->GetObjectFileNameWithoutTarget(*sf, dir_max,
&hasSourceExtension);
gt->Objects[sf] = objectName;
lg->AddLocalObjectFile(target, sf, objectName, hasSourceExtension);
}
}
//----------------------------------------------------------------------------
std::string EscapeJSON(const std::string& s) {
std::string result;
@ -378,6 +411,7 @@ void cmGlobalUnixMakefileGenerator3
(l->second.GetType() == cmTarget::STATIC_LIBRARY) ||
(l->second.GetType() == cmTarget::SHARED_LIBRARY) ||
(l->second.GetType() == cmTarget::MODULE_LIBRARY) ||
(l->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
(l->second.GetType() == cmTarget::UTILITY))
{
std::string tname = lg->GetRelativeTargetDirectory(l->second);
@ -413,6 +447,7 @@ cmGlobalUnixMakefileGenerator3
(l->second.GetType() == cmTarget::STATIC_LIBRARY) ||
(l->second.GetType() == cmTarget::SHARED_LIBRARY) ||
(l->second.GetType() == cmTarget::MODULE_LIBRARY) ||
(l->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
(l->second.GetType() == cmTarget::UTILITY))
{
// Add this to the list of depends rules in this directory.
@ -587,6 +622,7 @@ cmGlobalUnixMakefileGenerator3
(t->second.GetType() == cmTarget::STATIC_LIBRARY) ||
(t->second.GetType() == cmTarget::SHARED_LIBRARY) ||
(t->second.GetType() == cmTarget::MODULE_LIBRARY) ||
(t->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
(t->second.GetType() == cmTarget::UTILITY)))
{
// Add a rule to build the target by name.
@ -673,6 +709,7 @@ cmGlobalUnixMakefileGenerator3
|| (t->second.GetType() == cmTarget::STATIC_LIBRARY)
|| (t->second.GetType() == cmTarget::SHARED_LIBRARY)
|| (t->second.GetType() == cmTarget::MODULE_LIBRARY)
|| (t->second.GetType() == cmTarget::OBJECT_LIBRARY)
|| (t->second.GetType() == cmTarget::UTILITY)))
{
std::string makefileName;
@ -982,6 +1019,7 @@ void cmGlobalUnixMakefileGenerator3::WriteHelpRule
(t->second.GetType() == cmTarget::STATIC_LIBRARY) ||
(t->second.GetType() == cmTarget::SHARED_LIBRARY) ||
(t->second.GetType() == cmTarget::MODULE_LIBRARY) ||
(t->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
(t->second.GetType() == cmTarget::GLOBAL_TARGET) ||
(t->second.GetType() == cmTarget::UTILITY))
{

View File

@ -182,6 +182,8 @@ protected:
size_t CountProgressMarksInAll(cmLocalUnixMakefileGenerator3* lg);
cmGeneratedFileStream *CommandDatabase;
private:
virtual void ComputeTargetObjects(cmGeneratorTarget* gt) const;
};
#endif

View File

@ -72,7 +72,7 @@ public:
* Studio?
*/
virtual std::string GetUserMacrosRegKeyBase();
virtual const char* GetCMakeCFGInitDirectory()
virtual const char* GetCMakeCFGIntDir() const
{ return "$(Configuration)";}
bool Find64BitTools(cmMakefile* mf);
protected:

View File

@ -82,7 +82,7 @@ public:
std::string& dir);
///! What is the configurations directory variable called?
virtual const char* GetCMakeCFGInitDirectory() { return "$(IntDir)"; }
virtual const char* GetCMakeCFGIntDir() const { return "$(IntDir)"; }
protected:
virtual const char* GetIDEVersion() { return "6.0"; }

View File

@ -87,7 +87,7 @@ public:
std::string& dir);
///! What is the configurations directory variable called?
virtual const char* GetCMakeCFGInitDirectory() { return "$(OutDir)"; }
virtual const char* GetCMakeCFGIntDir() const { return "$(OutDir)"; }
/** Return true if the target project file should have the option
LinkLibraryDependencies and link to .sln dependencies. */

View File

@ -12,8 +12,10 @@
#include "cmGlobalVisualStudioGenerator.h"
#include "cmCallVisualStudioMacro.h"
#include "cmLocalGenerator.h"
#include "cmGeneratorTarget.h"
#include "cmLocalVisualStudioGenerator.h"
#include "cmMakefile.h"
#include "cmSourceFile.h"
#include "cmTarget.h"
//----------------------------------------------------------------------------
@ -97,6 +99,64 @@ void cmGlobalVisualStudioGenerator::Generate()
this->cmGlobalGenerator::Generate();
}
//----------------------------------------------------------------------------
void
cmGlobalVisualStudioGenerator
::ComputeTargetObjects(cmGeneratorTarget* gt) const
{
cmLocalVisualStudioGenerator* lg =
static_cast<cmLocalVisualStudioGenerator*>(gt->LocalGenerator);
std::string dir_max = lg->ComputeLongestObjectDirectory(*gt->Target);
// Count the number of object files with each name. Note that
// windows file names are not case sensitive.
std::map<cmStdString, int> counts;
for(std::vector<cmSourceFile*>::const_iterator
si = gt->ObjectSources.begin();
si != gt->ObjectSources.end(); ++si)
{
cmSourceFile* sf = *si;
std::string objectNameLower = cmSystemTools::LowerCase(
cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
objectNameLower += ".obj";
counts[objectNameLower] += 1;
}
// For all source files producing duplicate names we need unique
// object name computation.
for(std::vector<cmSourceFile*>::const_iterator
si = gt->ObjectSources.begin();
si != gt->ObjectSources.end(); ++si)
{
cmSourceFile* sf = *si;
std::string objectName =
cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
objectName += ".obj";
if(counts[cmSystemTools::LowerCase(objectName)] > 1)
{
gt->ExplicitObjectName.insert(sf);
objectName = lg->GetObjectFileNameWithoutTarget(*sf, dir_max);
}
gt->Objects[sf] = objectName;
}
std::string dir = gt->Makefile->GetCurrentOutputDirectory();
dir += "/";
std::string tgtDir = lg->GetTargetDirectory(*gt->Target);
if(!tgtDir.empty())
{
dir += tgtDir;
dir += "/";
}
const char* cd = this->GetCMakeCFGIntDir();
if(cd && *cd)
{
dir += cd;
dir += "/";
}
gt->ObjectDirectory = dir;
}
//----------------------------------------------------------------------------
bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
const std::string& regKeyBase,
@ -314,6 +374,12 @@ bool cmGlobalVisualStudioGenerator::ComputeTargetDepends()
return true;
}
//----------------------------------------------------------------------------
static bool VSLinkable(cmTarget* t)
{
return t->IsLinkable() || t->GetType() == cmTarget::OBJECT_LIBRARY;
}
//----------------------------------------------------------------------------
void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(cmTarget& target)
{
@ -398,7 +464,7 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(cmTarget& target)
di != utilDepends.end(); ++di)
{
cmTarget* dep = *di;
if(allowLinkable || !dep->IsLinkable() || linked.count(dep))
if(allowLinkable || !VSLinkable(dep) || linked.count(dep))
{
// Direct dependency allowed.
vsTargetDepend.insert(dep->GetName());

View File

@ -97,6 +97,8 @@ protected:
typedef std::map<cmTarget*, cmStdString> UtilityDependsMap;
UtilityDependsMap UtilityDepends;
private:
void ComputeTargetObjects(cmGeneratorTarget* gt) const;
void FollowLinkDepends(cmTarget* target, std::set<cmTarget*>& linked);
class TargetSetMap: public std::map<cmTarget*, TargetSet> {};

View File

@ -19,6 +19,7 @@
#include "cmComputeLinkInformation.h"
#include "cmSourceFile.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratorTarget.h"
#include <cmsys/auto_ptr.hxx>
@ -303,6 +304,10 @@ void cmGlobalXCodeGenerator::Generate()
}
this->ForceLinkerLanguages();
this->cmGlobalGenerator::Generate();
if(cmSystemTools::GetErrorOccuredFlag())
{
return;
}
for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
{
cmLocalGenerator* root = it->second[0];
@ -417,6 +422,8 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
// this will make sure that when the next target is built
// things are up-to-date
if((target.GetType() == cmTarget::EXECUTABLE ||
// Nope - no post-build for OBJECT_LIRBRARY
// target.GetType() == cmTarget::OBJECT_LIBRARY ||
target.GetType() == cmTarget::STATIC_LIBRARY ||
target.GetType() == cmTarget::SHARED_LIBRARY ||
target.GetType() == cmTarget::MODULE_LIBRARY))
@ -570,14 +577,42 @@ cmXCodeObject* cmGlobalXCodeGenerator
}
//----------------------------------------------------------------------------
cmStdString GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf)
cmStdString
GetGroupMapKeyFromPath(cmTarget& cmtarget, const std::string& fullpath)
{
cmStdString key(cmtarget.GetName());
key += "-";
key += sf->GetFullPath();
key += fullpath;
return key;
}
//----------------------------------------------------------------------------
cmStdString
GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf)
{
return GetGroupMapKeyFromPath(cmtarget, sf->GetFullPath());
}
//----------------------------------------------------------------------------
cmXCodeObject*
cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath(
const std::string &fullpath,
cmTarget& cmtarget,
const std::string &lang)
{
// Using a map and the full path guarantees that we will always get the same
// fileRef object for any given full path.
//
cmXCodeObject* fileRef =
this->CreateXCodeFileReferenceFromPath(fullpath, cmtarget, lang);
cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
buildFile->SetComment(fileRef->GetComment());
buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
return buildFile;
}
//----------------------------------------------------------------------------
cmXCodeObject*
cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
@ -612,14 +647,16 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
flags += flagsBuild.GetString();
}
// Using a map and the full path guarantees that we will always get the same
// fileRef object for any given full path.
//
cmXCodeObject* fileRef = this->CreateXCodeFileReference(sf, cmtarget);
const char* lang =
this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
if (!lang)
{
lang = "";
}
cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
buildFile->SetComment(fileRef->GetComment());
buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
cmXCodeObject* buildFile =
this->CreateXCodeSourceFileFromPath(sf->GetFullPath(), cmtarget, lang);
cmXCodeObject* fileRef = buildFile->GetObject("fileRef")->GetObject();
cmXCodeObject* settings =
this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
@ -671,36 +708,12 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
}
//----------------------------------------------------------------------------
cmXCodeObject*
cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
cmTarget& cmtarget)
std::string
GetSourcecodeValueFromFileExtension(const std::string& _ext,
const std::string& lang)
{
std::string fname = sf->GetFullPath();
cmXCodeObject* fileRef = this->FileRefs[fname];
if(!fileRef)
{
fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
std::string comment = fname;
//comment += " in ";
//std::string gname = group->GetObject("name")->GetString();
//comment += gname.substr(1, gname.size()-2);
fileRef->SetComment(fname.c_str());
this->FileRefs[fname] = fileRef;
}
cmStdString key = GetGroupMapKey(cmtarget, sf);
cmXCodeObject* group = this->GroupMap[key];
cmXCodeObject* children = group->GetObject("children");
if (!children->HasObject(fileRef))
{
children->AddObject(fileRef);
}
fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
const char* lang =
this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
std::string ext = cmSystemTools::LowerCase(_ext);
std::string sourcecode = "sourcecode";
std::string ext = sf->GetExtension();
ext = cmSystemTools::LowerCase(ext);
if(ext == "o")
{
@ -735,18 +748,6 @@ cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
{
sourcecode += ".cpp.h";
}
else if(lang && strcmp(lang, "CXX") == 0)
{
sourcecode += ".cpp.cpp";
}
else if(lang && strcmp(lang, "C") == 0)
{
sourcecode += ".c.c";
}
else if(lang && strcmp(lang, "Fortran") == 0)
{
sourcecode += ".fortran.f90";
}
else if(ext == "png" || ext == "gif" || ext == "jpg")
{
sourcecode = "image";
@ -755,6 +756,18 @@ cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
{
sourcecode += ".text";
}
else if(lang == "CXX")
{
sourcecode += ".cpp.cpp";
}
else if(lang == "C")
{
sourcecode += ".c.c";
}
else if(lang == "Fortran")
{
sourcecode += ".fortran.f90";
}
//else
// {
// // Already specialized above or we leave sourcecode == "sourcecode"
@ -763,11 +776,51 @@ cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
// // valid lastKnownFileType value.
// }
return sourcecode;
}
//----------------------------------------------------------------------------
cmXCodeObject*
cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
const std::string &fullpath,
cmTarget& cmtarget,
const std::string &lang)
{
std::string fname = fullpath;
cmXCodeObject* fileRef = this->FileRefs[fname];
if(!fileRef)
{
fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
std::string comment = fname;
fileRef->SetComment(fname.c_str());
this->FileRefs[fname] = fileRef;
}
cmStdString key = GetGroupMapKeyFromPath(cmtarget, fullpath);
cmXCodeObject* group = this->GroupMap[key];
cmXCodeObject* children = group->GetObject("children");
if (!children->HasObject(fileRef))
{
children->AddObject(fileRef);
}
fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
// Compute the extension.
std::string ext;
std::string realExt =
cmSystemTools::GetFilenameLastExtension(fullpath);
if(!realExt.empty())
{
// Extension without the leading '.'.
ext = realExt.substr(1);
}
std::string sourcecode = GetSourcecodeValueFromFileExtension(ext, lang);
fileRef->AddAttribute("lastKnownFileType",
this->CreateString(sourcecode.c_str()));
// Store the file path relative to the top of the source tree.
std::string path = this->RelativeToSource(sf->GetFullPath().c_str());
std::string path = this->RelativeToSource(fullpath.c_str());
std::string name = cmSystemTools::GetFilenameName(path.c_str());
const char* sourceTree = (cmSystemTools::FileIsFullPath(path.c_str())?
"<absolute>" : "SOURCE_ROOT");
@ -781,6 +834,22 @@ cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
return fileRef;
}
//----------------------------------------------------------------------------
cmXCodeObject*
cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
cmTarget& cmtarget)
{
const char* lang =
this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
if (!lang)
{
lang = "";
}
return this->CreateXCodeFileReferenceFromPath(
sf->GetFullPath(), cmtarget, lang);
}
//----------------------------------------------------------------------------
bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
{
@ -889,6 +958,20 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
}
}
// Add object library contents as external objects. (Equivalent to
// the externalObjFiles above, except each one is not a cmSourceFile
// within the target.)
std::vector<std::string> objs;
this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs);
for(std::vector<std::string>::const_iterator
oi = objs.begin(); oi != objs.end(); ++oi)
{
std::string obj = *oi;
cmXCodeObject* xsf =
this->CreateXCodeSourceFileFromPath(obj, cmtarget, "");
externalObjFiles.push_back(xsf);
}
// some build phases only apply to bundles and/or frameworks
bool isFrameworkTarget = cmtarget.IsFrameworkOnApple();
bool isBundleTarget = cmtarget.GetPropertyAsBool("MACOSX_BUNDLE");
@ -1494,7 +1577,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
std::string defFlags;
bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
(target.GetType() == cmTarget::MODULE_LIBRARY));
bool binary = ((target.GetType() == cmTarget::STATIC_LIBRARY) ||
bool binary = ((target.GetType() == cmTarget::OBJECT_LIBRARY) ||
(target.GetType() == cmTarget::STATIC_LIBRARY) ||
(target.GetType() == cmTarget::EXECUTABLE) ||
shared);
@ -1581,7 +1665,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
}
const char* linkFlagsProp = "LINK_FLAGS";
if(target.GetType() == cmTarget::STATIC_LIBRARY)
if(target.GetType() == cmTarget::OBJECT_LIBRARY ||
target.GetType() == cmTarget::STATIC_LIBRARY)
{
linkFlagsProp = "STATIC_LIBRARY_FLAGS";
}
@ -1635,11 +1720,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
std::string pnprefix;
std::string pnbase;
std::string pnsuffix;
target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
// Store the product name for all target types.
buildSettings->AddAttribute("PRODUCT_NAME",
this->CreateString(pnbase.c_str()));
target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
// Set attributes to specify the proper name for the target.
std::string pndir = this->CurrentMakefile->GetCurrentOutputDirectory();
@ -1663,17 +1745,44 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
this->CreateString(pndir.c_str()));
pndir = target.GetDirectory(configName);
}
buildSettings->AddAttribute("EXECUTABLE_PREFIX",
this->CreateString(pnprefix.c_str()));
buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
this->CreateString(pnsuffix.c_str()));
}
else if(target.GetType() == cmTarget::OBJECT_LIBRARY)
{
pnprefix = "lib";
pnbase = target.GetName();
pnsuffix = ".a";
if(this->XcodeVersion >= 21)
{
std::string pncdir = this->GetObjectsNormalDirectory(
this->CurrentProject, configName, &target);
buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR",
this->CreateString(pncdir.c_str()));
}
else
{
buildSettings->AddAttribute("OBJROOT",
this->CreateString(pndir.c_str()));
pndir = this->GetObjectsNormalDirectory(
this->CurrentProject, configName, &target);
}
}
// Store the product name for all target types.
buildSettings->AddAttribute("PRODUCT_NAME",
this->CreateString(pnbase.c_str()));
buildSettings->AddAttribute("SYMROOT",
this->CreateString(pndir.c_str()));
// Handle settings for each target type.
switch(target.GetType())
{
case cmTarget::OBJECT_LIBRARY:
case cmTarget::STATIC_LIBRARY:
{
buildSettings->AddAttribute("LIBRARY_STYLE",
@ -2177,6 +2286,7 @@ const char* cmGlobalXCodeGenerator::GetTargetFileType(cmTarget& cmtarget)
{
switch(cmtarget.GetType())
{
case cmTarget::OBJECT_LIBRARY:
case cmTarget::STATIC_LIBRARY:
return "archive.ar";
case cmTarget::MODULE_LIBRARY:
@ -2200,6 +2310,7 @@ const char* cmGlobalXCodeGenerator::GetTargetProductType(cmTarget& cmtarget)
{
switch(cmtarget.GetType())
{
case cmTarget::OBJECT_LIBRARY:
case cmTarget::STATIC_LIBRARY:
return "com.apple.product-type.library.static";
case cmTarget::MODULE_LIBRARY:
@ -2257,7 +2368,17 @@ cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
{
fileRef->AddAttribute("explicitFileType", this->CreateString(fileType));
}
std::string fullName = cmtarget.GetFullName(defConfig.c_str());
std::string fullName;
if(cmtarget.GetType() == cmTarget::OBJECT_LIBRARY)
{
fullName = "lib";
fullName += cmtarget.GetName();
fullName += ".a";
}
else
{
fullName = cmtarget.GetFullName(defConfig.c_str());
}
fileRef->AddAttribute("path", this->CreateString(fullName.c_str()));
fileRef->AddAttribute("refType", this->CreateString("0"));
fileRef->AddAttribute("sourceTree",
@ -2462,7 +2583,8 @@ void cmGlobalXCodeGenerator
}
// Skip link information for static libraries.
if(cmtarget->GetType() == cmTarget::STATIC_LIBRARY)
if(cmtarget->GetType() == cmTarget::OBJECT_LIBRARY ||
cmtarget->GetType() == cmTarget::STATIC_LIBRARY)
{
return;
}
@ -2610,6 +2732,7 @@ void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
std::vector<cmSourceFile*> classes = cmtarget.GetSourceFiles();
// Put cmSourceFile instances in proper groups:
for(std::vector<cmSourceFile*>::const_iterator s = classes.begin();
s != classes.end(); s++)
{
@ -2623,6 +2746,21 @@ void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
cmStdString key = GetGroupMapKey(cmtarget, sf);
this->GroupMap[key] = pbxgroup;
}
// Put OBJECT_LIBRARY objects in proper groups:
std::vector<std::string> objs;
this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs);
for(std::vector<std::string>::const_iterator
oi = objs.begin(); oi != objs.end(); ++oi)
{
std::string const& source = *oi;
cmSourceGroup& sourceGroup =
mf->FindSourceGroup(source.c_str(), sourceGroups);
cmXCodeObject* pbxgroup =
this->CreateOrGetPBXGroup(cmtarget, &sourceGroup);
cmStdString key = GetGroupMapKeyFromPath(cmtarget, source);
this->GroupMap[key] = pbxgroup;
}
}
}
}
@ -3054,6 +3192,26 @@ void cmGlobalXCodeGenerator
this->RootObject->AddAttribute("targets", allTargets);
}
//----------------------------------------------------------------------------
std::string
cmGlobalXCodeGenerator::GetObjectsNormalDirectory(
const std::string &projName,
const std::string &configName,
const cmTarget *t) const
{
std::string dir =
t->GetMakefile()->GetCurrentOutputDirectory();
dir += "/";
dir += projName;
dir += ".build/";
dir += configName;
dir += "/";
dir += t->GetName();
dir += ".build/Objects-normal/";
return dir;
}
//----------------------------------------------------------------------------
void
cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
@ -3123,6 +3281,8 @@ cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
cmTarget* t =target->GetTarget();
if(t->GetType() == cmTarget::EXECUTABLE ||
// Nope - no post-build for OBJECT_LIRBRARY
// t->GetType() == cmTarget::OBJECT_LIBRARY ||
t->GetType() == cmTarget::STATIC_LIBRARY ||
t->GetType() == cmTarget::SHARED_LIBRARY ||
t->GetType() == cmTarget::MODULE_LIBRARY)
@ -3178,15 +3338,8 @@ cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
// then remove those exectuables as well
if(this->Architectures.size() > 1)
{
std::string universal =
t->GetMakefile()->GetCurrentOutputDirectory();
universal += "/";
universal += this->CurrentProject;
universal += ".build/";
universal += configName;
universal += "/";
universal += t->GetName();
universal += ".build/Objects-normal/";
std::string universal = this->GetObjectsNormalDirectory(
this->CurrentProject, configName, t);
for( std::vector<std::string>::iterator arch =
this->Architectures.begin();
arch != this->Architectures.end(); ++arch)
@ -3292,7 +3445,7 @@ cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
}
//----------------------------------------------------------------------------
const char* cmGlobalXCodeGenerator::GetCMakeCFGInitDirectory()
const char* cmGlobalXCodeGenerator::GetCMakeCFGIntDir() const
{
return this->XcodeVersion >= 21 ?
"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)" : ".";
@ -3545,3 +3698,51 @@ bool cmGlobalXCodeGenerator::IsMultiConfig()
// Newer Xcode versions are multi config:
return true;
}
//----------------------------------------------------------------------------
void
cmGlobalXCodeGenerator
::ComputeTargetObjects(cmGeneratorTarget* gt) const
{
// Count the number of object files with each name. Warn about duplicate
// names since Xcode names them uniquely automatically with a numeric suffix
// to avoid exact duplicate file names. Note that Mac file names are not
// typically case sensitive, hence the LowerCase.
std::map<cmStdString, int> counts;
for(std::vector<cmSourceFile*>::const_iterator
si = gt->ObjectSources.begin();
si != gt->ObjectSources.end(); ++si)
{
cmSourceFile* sf = *si;
std::string objectName =
cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
objectName += ".o";
std::string objectNameLower = cmSystemTools::LowerCase(objectName);
counts[objectNameLower] += 1;
if (2 == counts[objectNameLower])
{
// TODO: emit warning about duplicate name?
}
gt->Objects[sf] = objectName;
}
const char* configName = this->GetCMakeCFGIntDir();
std::string dir = this->GetObjectsNormalDirectory(
this->CurrentProject, configName, gt->Target);
if(this->XcodeVersion >= 21)
{
dir += "$(CURRENT_ARCH)/";
}
else
{
#ifdef __ppc__
dir += "ppc/";
#endif
#ifdef __i386
dir += "i386/";
#endif
}
gt->ObjectDirectory = dir;
}

View File

@ -74,7 +74,7 @@ public:
std::string& dir);
///! What is the configurations directory variable called?
virtual const char* GetCMakeCFGInitDirectory();
virtual const char* GetCMakeCFGIntDir() const;
void SetCurrentLocalGenerator(cmLocalGenerator*);
@ -153,6 +153,12 @@ private:
std::vector<cmLocalGenerator*>& generators);
void WriteXCodePBXProj(std::ostream& fout, cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators);
cmXCodeObject* CreateXCodeFileReferenceFromPath(const std::string &fullpath,
cmTarget& cmtarget,
const std::string &lang);
cmXCodeObject* CreateXCodeSourceFileFromPath(const std::string &fullpath,
cmTarget& cmtarget,
const std::string &lang);
cmXCodeObject* CreateXCodeFileReference(cmSourceFile* sf,
cmTarget& cmtarget);
cmXCodeObject* CreateXCodeSourceFile(cmLocalGenerator* gen,
@ -200,6 +206,13 @@ protected:
std::vector<cmXCodeObject*> XCodeObjects;
cmXCodeObject* RootObject;
private:
void ComputeTargetObjects(cmGeneratorTarget* gt) const;
std::string GetObjectsNormalDirectory(
const std::string &projName,
const std::string &configName,
const cmTarget *t) const;
void addObject(cmXCodeObject *obj);
std::string PostBuildMakeTarget(std::string const& tName,
std::string const& configName);

View File

@ -357,7 +357,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
if(target->GetType() != cmTarget::EXECUTABLE &&
target->GetType() != cmTarget::STATIC_LIBRARY &&
target->GetType() != cmTarget::SHARED_LIBRARY &&
target->GetType() != cmTarget::MODULE_LIBRARY)
target->GetType() != cmTarget::MODULE_LIBRARY &&
target->GetType() != cmTarget::OBJECT_LIBRARY)
{
cmOStringStream e;
e << "TARGETS given target \"" << (*targetIt)
@ -365,6 +366,14 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
this->SetError(e.str().c_str());
return false;
}
else if(target->GetType() == cmTarget::OBJECT_LIBRARY)
{
cmOStringStream e;
e << "TARGETS given OBJECT library \"" << (*targetIt)
<< "\" which may not be installed.";
this->SetError(e.str().c_str());
return false;
}
// Store the target in the list to be installed.
targets.push_back(target);
}

View File

@ -90,6 +90,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
case cmTarget::STATIC_LIBRARY: type = cmInstallType_STATIC_LIBRARY; break;
case cmTarget::SHARED_LIBRARY: type = cmInstallType_SHARED_LIBRARY; break;
case cmTarget::MODULE_LIBRARY: type = cmInstallType_MODULE_LIBRARY; break;
case cmTarget::OBJECT_LIBRARY:
case cmTarget::UTILITY:
case cmTarget::GLOBAL_TARGET:
case cmTarget::UNKNOWN_LIBRARY:

View File

@ -1914,6 +1914,10 @@ bool cmLocalGenerator::GetRealDependency(const char* inName,
case cmTarget::UNKNOWN_LIBRARY:
dep = target->GetLocation(config);
return true;
case cmTarget::OBJECT_LIBRARY:
// An object library has no single file on which to depend.
// This was listed to get the target-level dependency.
return false;
case cmTarget::UTILITY:
case cmTarget::GLOBAL_TARGET:
// A utility target has no file on which to depend. This was listed

View File

@ -117,37 +117,6 @@ cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator()
return static_cast<cmGlobalNinjaGenerator*>(this->GetGlobalGenerator());
}
// TODO: Picked up from cmLocalUnixMakefileGenerator3. Refactor it.
std::string
cmLocalNinjaGenerator
::GetObjectFileName(const cmTarget& target,
const cmSourceFile& source)
{
// Make sure we never hit this old case.
if(source.GetProperty("MACOSX_PACKAGE_LOCATION"))
{
std::string msg = "MACOSX_PACKAGE_LOCATION set on source file: ";
msg += source.GetFullPath();
this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR,
msg.c_str());
}
// Start with the target directory.
std::string obj = this->GetTargetDirectory(target);
obj += "/";
// Get the object file name without the target directory.
std::string dir_max;
dir_max += this->Makefile->GetCurrentOutputDirectory();
dir_max += "/";
dir_max += obj;
std::string objectName =
this->GetObjectFileNameWithoutTarget(source, dir_max, 0);
// Append the object name to the target directory.
obj += objectName;
return obj;
}
//----------------------------------------------------------------------------
// Virtual protected methods.

View File

@ -59,9 +59,6 @@ public:
const char* GetConfigName() const
{ return this->ConfigName.c_str(); }
std::string GetObjectFileName(const cmTarget& target,
const cmSourceFile& source);
/// @return whether we are processing the top CMakeLists.txt file.
bool isRootMakefile() const;

View File

@ -358,6 +358,7 @@ void cmLocalUnixMakefileGenerator3
(t->second.GetType() == cmTarget::STATIC_LIBRARY) ||
(t->second.GetType() == cmTarget::SHARED_LIBRARY) ||
(t->second.GetType() == cmTarget::MODULE_LIBRARY) ||
(t->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
(t->second.GetType() == cmTarget::UTILITY))
{
emitted.insert(t->second.GetName());
@ -2008,45 +2009,6 @@ void cmLocalUnixMakefileGenerator3
}
}
//----------------------------------------------------------------------------
std::string
cmLocalUnixMakefileGenerator3
::GetObjectFileName(cmTarget& target,
const cmSourceFile& source,
std::string* nameWithoutTargetDir,
bool* hasSourceExtension)
{
// Make sure we never hit this old case.
if(source.GetProperty("MACOSX_PACKAGE_LOCATION"))
{
std::string msg = "MACOSX_PACKAGE_LOCATION set on source file: ";
msg += source.GetFullPath();
this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR,
msg.c_str());
}
// Start with the target directory.
std::string obj = this->GetTargetDirectory(target);
obj += "/";
// Get the object file name without the target directory.
std::string dir_max;
dir_max += this->Makefile->GetCurrentOutputDirectory();
dir_max += "/";
dir_max += obj;
std::string objectName =
this->GetObjectFileNameWithoutTarget(source, dir_max,
hasSourceExtension);
if(nameWithoutTargetDir)
{
*nameWithoutTargetDir = objectName;
}
// Append the object name to the target directory.
obj += objectName;
return obj;
}
//----------------------------------------------------------------------------
void cmLocalUnixMakefileGenerator3::WriteDisclaimer(std::ostream& os)
{

View File

@ -284,11 +284,6 @@ protected:
cmTarget& target,
const std::vector<std::string>& objects);
std::string GetObjectFileName(cmTarget& target,
const cmSourceFile& source,
std::string* nameWithoutTargetDir = 0,
bool* hasSourceExtension = 0);
void AppendRuleDepend(std::vector<std::string>& depends,
const char* ruleFileName);
void AppendRuleDepends(std::vector<std::string>& depends,

View File

@ -15,6 +15,7 @@
#include "cmSystemTools.h"
#include "cmSourceFile.h"
#include "cmCacheManager.h"
#include "cmGeneratorTarget.h"
#include "cmake.h"
#include "cmComputeLinkInformation.h"
@ -126,6 +127,7 @@ void cmLocalVisualStudio6Generator::OutputDSPFile()
switch(l->second.GetType())
{
case cmTarget::STATIC_LIBRARY:
case cmTarget::OBJECT_LIBRARY:
this->SetBuildType(STATIC_LIBRARY, l->first.c_str(), l->second);
break;
case cmTarget::SHARED_LIBRARY:
@ -336,9 +338,6 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout,
}
}
// Compute which sources need unique object computation.
this->ComputeObjectNameRequirements(classes);
// Write the DSP file's header.
this->WriteDSPHeader(fout, libName, target, sourceGroups);
@ -358,6 +357,8 @@ void cmLocalVisualStudio6Generator
::WriteGroup(const cmSourceGroup *sg, cmTarget& target,
std::ostream &fout, const char *libName)
{
cmGeneratorTarget* gt =
this->GlobalGenerator->GetGeneratorTarget(&target);
const std::vector<const cmSourceFile *> &sourceFiles =
sg->GetSourceFiles();
// If the group is empty, don't write it at all.
@ -374,28 +375,6 @@ void cmLocalVisualStudio6Generator
this->WriteDSPBeginGroup(fout, name.c_str(), "");
}
// Compute the maximum length configuration name.
std::string config_max;
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(config.size() > config_max.size())
{
config_max = config;
}
}
// Compute the maximum length full path to the intermediate
// files directory for any configuration. This is used to construct
// object file names that do not produce paths that are too long.
std::string dir_max;
dir_max += this->Makefile->GetCurrentOutputDirectory();
dir_max += "/";
dir_max += config_max;
dir_max += "/";
// Loop through each source in the source group.
for(std::vector<const cmSourceFile *>::const_iterator sf =
sourceFiles.begin(); sf != sourceFiles.end(); ++sf)
@ -406,11 +385,9 @@ void cmLocalVisualStudio6Generator
std::string compileFlags;
std::vector<std::string> depends;
std::string objectNameDir;
if(this->NeedObjectName.find(*sf) != this->NeedObjectName.end())
if(gt->ExplicitObjectName.find(*sf) != gt->ExplicitObjectName.end())
{
objectNameDir =
cmSystemTools::GetFilenamePath(
this->GetObjectFileNameWithoutTarget(*(*sf), dir_max));
objectNameDir = cmSystemTools::GetFilenamePath(gt->Objects[*sf]);
}
// Add per-source file flags.
@ -1264,8 +1241,18 @@ void cmLocalVisualStudio6Generator
outputNameMinSizeRel = target.GetFullName("MinSizeRel");
outputNameRelWithDebInfo = target.GetFullName("RelWithDebInfo");
}
else if(target.GetType() == cmTarget::OBJECT_LIBRARY)
{
outputName = target.GetName();
outputName += ".lib";
outputNameDebug = outputName;
outputNameRelease = outputName;
outputNameMinSizeRel = outputName;
outputNameRelWithDebInfo = outputName;
}
// Compute the output directory for the target.
std::string outputDirOld;
std::string outputDirDebug;
std::string outputDirRelease;
std::string outputDirMinSizeRel;
@ -1275,6 +1262,11 @@ void cmLocalVisualStudio6Generator
target.GetType() == cmTarget::SHARED_LIBRARY ||
target.GetType() == cmTarget::MODULE_LIBRARY)
{
#ifdef CM_USE_OLD_VS6
outputDirOld =
removeQuotes(this->ConvertToOptionallyRelativeOutputPath
(target.GetDirectory().c_str()));
#endif
outputDirDebug =
removeQuotes(this->ConvertToOptionallyRelativeOutputPath(
target.GetDirectory("Debug").c_str()));
@ -1288,6 +1280,14 @@ void cmLocalVisualStudio6Generator
removeQuotes(this->ConvertToOptionallyRelativeOutputPath(
target.GetDirectory("RelWithDebInfo").c_str()));
}
else if(target.GetType() == cmTarget::OBJECT_LIBRARY)
{
std::string outputDir = cmake::GetCMakeFilesDirectoryPostSlash();
outputDirDebug = outputDir + "Debug";
outputDirRelease = outputDir + "Release";
outputDirMinSizeRel = outputDir + "MinSizeRel";
outputDirRelWithDebInfo = outputDir + "RelWithDebInfo";
}
// Compute the proper link information for the target.
std::string optionsDebug;
@ -1428,6 +1428,16 @@ void cmLocalVisualStudio6Generator
staticLibOptionsRelWithDebInfo += " ";
staticLibOptionsRelWithDebInfo = libflagsRelWithDebInfo;
}
std::string objects;
this->OutputObjects(target, "LIB", objects);
if(!objects.empty())
{
objects = "\n" + objects;
staticLibOptionsDebug += objects;
staticLibOptionsRelease += objects;
staticLibOptionsMinSizeRel += objects;
staticLibOptionsRelWithDebInfo += objects;
}
}
// Add the export symbol definition for shared library objects.
@ -1456,7 +1466,8 @@ void cmLocalVisualStudio6Generator
libnameExports.c_str());
cmSystemTools::ReplaceString(line, "CMAKE_MFC_FLAG",
mfcFlag);
if(target.GetType() == cmTarget::STATIC_LIBRARY )
if(target.GetType() == cmTarget::STATIC_LIBRARY ||
target.GetType() == cmTarget::OBJECT_LIBRARY)
{
cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS_DEBUG",
staticLibOptionsDebug.c_str());
@ -1555,7 +1566,7 @@ void cmLocalVisualStudio6Generator
(exePath.c_str())).c_str());
#endif
if(targetBuilds)
if(targetBuilds || target.GetType() == cmTarget::OBJECT_LIBRARY)
{
cmSystemTools::ReplaceString(line, "OUTPUT_DIRECTORY_DEBUG",
outputDirDebug.c_str());
@ -1565,13 +1576,11 @@ void cmLocalVisualStudio6Generator
outputDirMinSizeRel.c_str());
cmSystemTools::ReplaceString(line, "OUTPUT_DIRECTORY_RELWITHDEBINFO",
outputDirRelWithDebInfo.c_str());
#ifdef CM_USE_OLD_VS6
std::string outPath = target.GetDirectory();
cmSystemTools::ReplaceString
(line, "OUTPUT_DIRECTORY",
removeQuotes(this->ConvertToOptionallyRelativeOutputPath
(outPath.c_str())).c_str());
#endif
if(!outputDirOld.empty())
{
cmSystemTools::ReplaceString(line, "OUTPUT_DIRECTORY",
outputDirOld.c_str());
}
}
cmSystemTools::ReplaceString(line,
@ -1588,7 +1597,7 @@ void cmLocalVisualStudio6Generator
std::string flagsDebug = " ";
std::string flagsDebugRel = " ";
if(target.GetType() >= cmTarget::EXECUTABLE &&
target.GetType() <= cmTarget::MODULE_LIBRARY)
target.GetType() <= cmTarget::OBJECT_LIBRARY)
{
const char* linkLanguage = target.GetLinkerLanguage();
if(!linkLanguage)
@ -1743,6 +1752,8 @@ void cmLocalVisualStudio6Generator
ItemVector const& linkLibs = cli.GetItems();
std::vector<std::string> const& linkDirs = cli.GetDirectories();
this->OutputObjects(target, "LINK", options);
// Build the link options code.
for(std::vector<std::string>::const_iterator d = linkDirs.begin();
d != linkDirs.end(); ++d)
@ -1787,6 +1798,28 @@ void cmLocalVisualStudio6Generator
}
}
//----------------------------------------------------------------------------
void cmLocalVisualStudio6Generator
::OutputObjects(cmTarget& target, const char* tool,
std::string& options)
{
// VS 6 does not support per-config source locations so we
// list object library content on the link line instead.
cmGeneratorTarget* gt =
this->GlobalGenerator->GetGeneratorTarget(&target);
std::vector<std::string> objs;
gt->UseObjectLibraries(objs);
for(std::vector<std::string>::const_iterator
oi = objs.begin(); oi != objs.end(); ++oi)
{
options += "# ADD ";
options += tool;
options += "32 ";
options += this->ConvertToOptionallyRelativeOutputPath(oi->c_str());
options += "\n";
}
}
std::string
cmLocalVisualStudio6Generator
::GetTargetDirectory(cmTarget const&) const
@ -1795,6 +1828,36 @@ cmLocalVisualStudio6Generator
return "";
}
//----------------------------------------------------------------------------
std::string
cmLocalVisualStudio6Generator
::ComputeLongestObjectDirectory(cmTarget&) const
{
// Compute the maximum length configuration name.
std::string config_max;
for(std::vector<std::string>::const_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(config.size() > config_max.size())
{
config_max = config;
}
}
// Compute the maximum length full path to the intermediate
// files directory for any configuration. This is used to construct
// object file names that do not produce paths that are too long.
std::string dir_max;
dir_max += this->Makefile->GetCurrentOutputDirectory();
dir_max += "/";
dir_max += config_max;
dir_max += "/";
return dir_max;
}
std::string
cmLocalVisualStudio6Generator
::GetConfigName(std::string const& configuration) const

View File

@ -50,6 +50,7 @@ public:
void SetBuildType(BuildType, const char* libName, cmTarget&);
virtual std::string GetTargetDirectory(cmTarget const& target) const;
virtual std::string ComputeLongestObjectDirectory(cmTarget&) const;
private:
std::string DSPHeaderTemplate;
std::string DSPFooterTemplate;
@ -86,6 +87,8 @@ private:
void ComputeLinkOptions(cmTarget& target, const char* configName,
const std::string extraOptions,
std::string& options);
void OutputObjects(cmTarget& target, const char* tool,
std::string& options);
std::string GetTargetIncludeOptions(cmTarget &target);
std::vector<std::string> Configurations;

View File

@ -17,6 +17,7 @@
#include "cmSystemTools.h"
#include "cmSourceFile.h"
#include "cmCacheManager.h"
#include "cmGeneratorTarget.h"
#include "cmake.h"
#include "cmComputeLinkInformation.h"
@ -38,6 +39,7 @@ public:
LocalGenerator(e) {}
typedef cmComputeLinkInformation::ItemVector ItemVector;
void OutputLibraries(std::ostream& fout, ItemVector const& libs);
void OutputObjects(std::ostream& fout, cmTarget* t, const char* isep = 0);
private:
cmLocalVisualStudio7Generator* LocalGenerator;
};
@ -641,6 +643,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
bool targetBuilds = true;
switch(target.GetType())
{
case cmTarget::OBJECT_LIBRARY:
targetBuilds = false; // TODO: PDB for object library?
case cmTarget::STATIC_LIBRARY:
projectType = "typeStaticLibrary";
configType = "4";
@ -1000,6 +1004,22 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
}
switch(target.GetType())
{
case cmTarget::OBJECT_LIBRARY:
{
std::string libpath = this->GetTargetDirectory(target);
libpath += "/";
libpath += configName;
libpath += "/";
libpath += target.GetName();
libpath += ".lib";
const char* tool =
this->FortranProject? "VFLibrarianTool":"VCLibrarianTool";
fout << "\t\t\t<Tool\n"
<< "\t\t\t\tName=\"" << tool << "\"\n";
fout << "\t\t\t\tOutputFile=\""
<< this->ConvertToXMLOutputPathSingle(libpath.c_str()) << "\"/>\n";
break;
}
case cmTarget::STATIC_LIBRARY:
{
std::string targetNameFull = target.GetFullName(configName);
@ -1014,6 +1034,15 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
fout << "\t\t\t<Tool\n"
<< "\t\t\t\tName=\"" << tool << "\"\n";
if(this->GetVersion() < VS8)
{
cmOStringStream libdeps;
this->Internal->OutputObjects(libdeps, &target);
if(!libdeps.str().empty())
{
fout << "\t\t\t\tAdditionalDependencies=\"" << libdeps.str() << "\"\n";
}
}
std::string libflags;
if(const char* flags = target.GetProperty("STATIC_LIBRARY_FLAGS"))
{
@ -1074,8 +1103,12 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
// Use the NOINHERIT macro to avoid getting VS project default
// libraries which may be set by the user to something bad.
fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
<< this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
<< " ";
<< this->Makefile->GetSafeDefinition(standardLibsVar.c_str());
if(this->GetVersion() < VS8)
{
this->Internal->OutputObjects(fout, &target, " ");
}
fout << " ";
this->Internal->OutputLibraries(fout, cli.GetItems());
fout << "\"\n";
temp = target.GetDirectory(configName);
@ -1155,8 +1188,12 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
// Use the NOINHERIT macro to avoid getting VS project default
// libraries which may be set by the user to something bad.
fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
<< this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
<< " ";
<< this->Makefile->GetSafeDefinition(standardLibsVar.c_str());
if(this->GetVersion() < VS8)
{
this->Internal->OutputObjects(fout, &target, " ");
}
fout << " ";
this->Internal->OutputLibraries(fout, cli.GetItems());
fout << "\"\n";
temp = target.GetDirectory(configName);
@ -1242,6 +1279,30 @@ cmLocalVisualStudio7GeneratorInternals
}
}
//----------------------------------------------------------------------------
void
cmLocalVisualStudio7GeneratorInternals
::OutputObjects(std::ostream& fout, cmTarget* t, const char* isep)
{
// VS < 8 does not support per-config source locations so we
// list object library content on the link line instead.
cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
cmGeneratorTarget* gt =
lg->GetGlobalGenerator()->GetGeneratorTarget(t);
std::vector<std::string> objs;
gt->UseObjectLibraries(objs);
const char* sep = isep? isep : "";
for(std::vector<std::string>::const_iterator
oi = objs.begin(); oi != objs.end(); ++oi)
{
std::string rel = lg->Convert(oi->c_str(),
cmLocalGenerator::START_OUTPUT,
cmLocalGenerator::UNCHANGED);
fout << sep << lg->ConvertToXMLOutputPath(rel.c_str());
sep = " ";
}
}
//----------------------------------------------------------------------------
void
cmLocalVisualStudio7Generator
@ -1310,9 +1371,6 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
sourceGroup.AssignSource(*i);
}
// Compute which sources need unique object computation.
this->ComputeObjectNameRequirements(classes);
// open the project
this->WriteProjectStart(fout, libName, target, sourceGroups);
// write the configuration information
@ -1328,7 +1386,27 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
this->WriteGroup(&sg, target, fout, libName, configs);
}
//}
if(this->GetVersion() >= VS8)
{
// VS >= 8 support per-config source locations so we
// list object library content as external objects.
cmGeneratorTarget* gt =
this->GlobalGenerator->GetGeneratorTarget(&target);
std::vector<std::string> objs;
gt->UseObjectLibraries(objs);
if(!objs.empty())
{
// TODO: Separate sub-filter for each object library used?
fout << "\t\t<Filter Name=\"Object Libraries\">\n";
for(std::vector<std::string>::const_iterator
oi = objs.begin(); oi != objs.end(); ++oi)
{
std::string o = this->ConvertToXMLOutputPathSingle(oi->c_str());
fout << "\t\t\t<File RelativePath=\"" << o << "\" />\n";
}
fout << "\t\t</Filter>\n";
}
}
fout << "\t</Files>\n";
@ -1352,8 +1430,7 @@ public:
cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg,
cmTarget& target,
cmSourceFile const& sf,
std::vector<std::string>* configs,
std::string const& dir_max);
std::vector<std::string>* configs);
std::map<cmStdString, cmLVS7GFileConfig> FileConfigMap;
};
@ -1361,13 +1438,14 @@ cmLocalVisualStudio7GeneratorFCInfo
::cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg,
cmTarget& target,
cmSourceFile const& sf,
std::vector<std::string>* configs,
std::string const& dir_max)
std::vector<std::string>* configs)
{
cmGeneratorTarget* gt =
lg->GetGlobalGenerator()->GetGeneratorTarget(&target);
std::string objectName;
if(lg->NeedObjectName.find(&sf) != lg->NeedObjectName.end())
if(gt->ExplicitObjectName.find(&sf) != gt->ExplicitObjectName.end())
{
objectName = lg->GetObjectFileNameWithoutTarget(sf, dir_max);
objectName = gt->Objects[&sf];
}
// Compute per-source, per-config information.
@ -1478,11 +1556,11 @@ cmLocalVisualStudio7GeneratorFCInfo
}
}
void cmLocalVisualStudio7Generator
::ComputeMaxDirectoryLength(std::string& maxdir,
cmTarget& target)
{
//----------------------------------------------------------------------------
std::string
cmLocalVisualStudio7Generator
::ComputeLongestObjectDirectory(cmTarget& target) const
{
std::vector<std::string> *configs =
static_cast<cmGlobalVisualStudio7Generator *>
(this->GlobalGenerator)->GetConfigurations();
@ -1507,7 +1585,7 @@ void cmLocalVisualStudio7Generator
dir_max += "/";
dir_max += config_max;
dir_max += "/";
maxdir = dir_max;
return dir_max;
}
void cmLocalVisualStudio7Generator
@ -1530,19 +1608,13 @@ void cmLocalVisualStudio7Generator
this->WriteVCProjBeginGroup(fout, name.c_str(), "");
}
// Compute the maximum length full path to the intermediate
// files directory for any configuration. This is used to construct
// object file names that do not produce paths that are too long.
std::string dir_max;
this->ComputeMaxDirectoryLength(dir_max, target);
// Loop through each source in the source group.
std::string objectName;
for(std::vector<const cmSourceFile *>::const_iterator sf =
sourceFiles.begin(); sf != sourceFiles.end(); ++sf)
{
std::string source = (*sf)->GetFullPath();
FCInfo fcinfo(this, target, *(*sf), configs, dir_max);
FCInfo fcinfo(this, target, *(*sf), configs);
if (source != libName || target.GetType() == cmTarget::UTILITY ||
target.GetType() == cmTarget::GLOBAL_TARGET )

View File

@ -60,11 +60,7 @@ public:
virtual std::string GetTargetDirectory(cmTarget const&) const;
cmSourceFile* CreateVCProjBuildRule();
void WriteStampFiles();
// Compute the maximum length full path to the intermediate
// files directory for any configuration. This is used to construct
// object file names that do not produce paths that are too long.
void ComputeMaxDirectoryLength(std::string& maxdir,
cmTarget& target);
virtual std::string ComputeLongestObjectDirectory(cmTarget&) const;
virtual void ReadAndStoreExternalGUID(const char* name,
const char* path);

View File

@ -64,69 +64,6 @@ cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmTarget& target,
return pcc;
}
//----------------------------------------------------------------------------
bool cmLocalVisualStudioGenerator::SourceFileCompiles(const cmSourceFile* sf)
{
// Identify the language of the source file.
if(const char* lang = this->GetSourceFileLanguage(*sf))
{
// Check whether this source will actually be compiled.
return (!sf->GetCustomCommand() &&
!sf->GetPropertyAsBool("HEADER_FILE_ONLY") &&
!sf->GetPropertyAsBool("EXTERNAL_OBJECT"));
}
else
{
// Unknown source file language. Assume it will not be compiled.
return false;
}
}
//----------------------------------------------------------------------------
void
cmLocalVisualStudioGenerator::ComputeObjectNameRequirements(
std::vector<cmSourceFile*> const& sources
)
{
// Clear the current set of requirements.
this->NeedObjectName.clear();
// Count the number of object files with each name. Note that
// windows file names are not case sensitive.
std::map<cmStdString, int> counts;
for(std::vector<cmSourceFile*>::const_iterator s = sources.begin();
s != sources.end(); ++s)
{
const cmSourceFile* sf = *s;
if(this->SourceFileCompiles(sf))
{
std::string objectName = cmSystemTools::LowerCase(
cmSystemTools::GetFilenameWithoutLastExtension(
sf->GetFullPath()));
objectName += ".obj";
counts[objectName] += 1;
}
}
// For all source files producing duplicate names we need unique
// object name computation.
for(std::vector<cmSourceFile*>::const_iterator s = sources.begin();
s != sources.end(); ++s)
{
const cmSourceFile* sf = *s;
if(this->SourceFileCompiles(sf))
{
std::string objectName = cmSystemTools::LowerCase(
cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
objectName += ".obj";
if(counts[objectName] > 1)
{
this->NeedObjectName.insert(sf);
}
}
}
}
//----------------------------------------------------------------------------
const char* cmLocalVisualStudioGenerator::ReportErrorLabel() const
{

View File

@ -56,6 +56,8 @@ public:
/** Version of Visual Studio. */
VSVersion GetVersion() const { return this->Version; }
virtual std::string ComputeLongestObjectDirectory(cmTarget&) const = 0;
protected:
virtual const char* ReportErrorLabel() const;
virtual bool CustomCommandUseLocal() const { return false; }
@ -64,12 +66,6 @@ protected:
cmsys::auto_ptr<cmCustomCommand>
MaybeCreateImplibDir(cmTarget& target, const char* config, bool isFortran);
// Safe object file name generation.
void ComputeObjectNameRequirements(std::vector<cmSourceFile*> const&);
bool SourceFileCompiles(const cmSourceFile* sf);
std::set<const cmSourceFile*> NeedObjectName;
friend class cmVisualStudio10TargetGenerator;
VSVersion Version;
};

View File

@ -782,6 +782,7 @@ void cmMakefile::SetLocalGenerator(cmLocalGenerator* lg)
"\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$");
this->AddSourceGroup("CMake Rules", "\\.rule$");
this->AddSourceGroup("Resources", "\\.plist$");
this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
#endif
this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused();
@ -853,6 +854,14 @@ cmMakefile::AddCustomCommandToTarget(const char* target,
cmTargets::iterator ti = this->Targets.find(target);
if(ti != this->Targets.end())
{
if(ti->second.GetType() == cmTarget::OBJECT_LIBRARY)
{
cmOStringStream e;
e << "Target \"" << target << "\" is an OBJECT library "
"that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
this->IssueMessage(cmake::FATAL_ERROR, e.str());
return;
}
// Add the command to the appropriate build step for the target.
std::vector<std::string> no_output;
cmCustomCommand cc(this, no_output, depends,
@ -945,7 +954,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
outName += ".rule";
const char* dir =
this->LocalGenerator->GetGlobalGenerator()->
GetCMakeCFGInitDirectory();
GetCMakeCFGIntDir();
if(dir && dir[0] == '$')
{
cmSystemTools::ReplaceString(outName, dir,
@ -1912,8 +1921,11 @@ cmTarget* cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type,
// wrong type ? default to STATIC
if ( (type != cmTarget::STATIC_LIBRARY)
&& (type != cmTarget::SHARED_LIBRARY)
&& (type != cmTarget::MODULE_LIBRARY))
&& (type != cmTarget::MODULE_LIBRARY)
&& (type != cmTarget::OBJECT_LIBRARY))
{
this->IssueMessage(cmake::INTERNAL_ERROR,
"cmMakefile::AddLibrary given invalid target type.");
type = cmTarget::STATIC_LIBRARY;
}
@ -2865,7 +2877,7 @@ void cmMakefile::EnableLanguage(std::vector<std::string> const & lang,
{
this->AddDefinition("CMAKE_CFG_INTDIR",
this->LocalGenerator->GetGlobalGenerator()
->GetCMakeCFGInitDirectory());
->GetCMakeCFGIntDir());
this->LocalGenerator->GetGlobalGenerator()->EnableLanguage(lang, this,
optional);
}

View File

@ -101,6 +101,9 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
this->WriteModuleLibraryRules(true);
}
break;
case cmTarget::OBJECT_LIBRARY:
this->WriteObjectLibraryRules();
break;
default:
// If language is not known, this is an error.
cmSystemTools::Error("Unknown Library Type");
@ -121,6 +124,29 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
this->CloseFileStreams();
}
//----------------------------------------------------------------------------
void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules()
{
std::vector<std::string> commands;
std::vector<std::string> depends;
// Add post-build rules.
this->LocalGenerator->
AppendCustomCommands(commands, this->Target->GetPostBuildCommands(),
this->Target);
// Depend on the object files.
this->AppendObjectDepends(depends);
// Write the rule.
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
this->Target->GetName(),
depends, commands, true);
// Write the main driver rule to build everything in this target.
this->WriteTargetDriverRule(this->Target->GetName(), false);
}
//----------------------------------------------------------------------------
void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
{

View File

@ -25,6 +25,7 @@ public:
virtual void WriteRuleFiles();
protected:
void WriteObjectLibraryRules();
void WriteStaticLibraryRules();
void WriteSharedLibraryRules(bool relink);
void WriteModuleLibraryRules(bool relink);

View File

@ -11,6 +11,7 @@
============================================================================*/
#include "cmMakefileTargetGenerator.h"
#include "cmGeneratorTarget.h"
#include "cmGeneratedFileStream.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalUnixMakefileGenerator3.h"
@ -42,6 +43,7 @@ cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmTarget* target)
this->GlobalGenerator =
static_cast<cmGlobalUnixMakefileGenerator3*>(
this->LocalGenerator->GetGlobalGenerator());
this->GeneratorTarget = this->GlobalGenerator->GetGeneratorTarget(target);
cmake* cm = this->GlobalGenerator->GetCMakeInstance();
this->NoRuleMessages = false;
if(const char* ruleStatus = cm->GetProperty("RULE_MESSAGES"))
@ -63,6 +65,7 @@ cmMakefileTargetGenerator::New(cmTarget *tgt)
case cmTarget::STATIC_LIBRARY:
case cmTarget::SHARED_LIBRARY:
case cmTarget::MODULE_LIBRARY:
case cmTarget::OBJECT_LIBRARY:
result = new cmMakefileLibraryTargetGenerator(tgt);
break;
case cmTarget::UTILITY:
@ -131,58 +134,49 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
// First generate the object rule files. Save a list of all object
// files for this target.
const std::vector<cmSourceFile*>& sources = this->Target->GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
source != sources.end(); ++source)
for(std::vector<cmSourceFile*>::const_iterator
si = this->GeneratorTarget->CustomCommands.begin();
si != this->GeneratorTarget->CustomCommands.end(); ++si)
{
cmTarget::SourceFileFlags tsFlags =
this->Target->GetTargetSourceFileFlags(*source);
if(cmCustomCommand* cc = (*source)->GetCustomCommand())
cmCustomCommand const* cc = (*si)->GetCustomCommand();
this->GenerateCustomRuleFile(*cc);
if (clean)
{
this->GenerateCustomRuleFile(*cc);
if (clean)
const std::vector<std::string>& outputs = cc->GetOutputs();
for(std::vector<std::string>::const_iterator o = outputs.begin();
o != outputs.end(); ++o)
{
const std::vector<std::string>& outputs = cc->GetOutputs();
for(std::vector<std::string>::const_iterator o = outputs.begin();
o != outputs.end(); ++o)
{
this->CleanFiles.push_back
(this->Convert(o->c_str(),
cmLocalGenerator::START_OUTPUT,
cmLocalGenerator::UNCHANGED));
}
}
}
else if(tsFlags.Type != cmTarget::SourceFileTypeNormal)
{
this->WriteMacOSXContentRules(*(*source), tsFlags.MacFolder);
}
else if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY"))
{
if(!this->GlobalGenerator->IgnoreFile
((*source)->GetExtension().c_str()))
{
// Generate this object file's rule file.
this->WriteObjectRuleFiles(*(*source));
}
else if((*source)->GetPropertyAsBool("EXTERNAL_OBJECT"))
{
// This is an external object file. Just add it.
this->ExternalObjects.push_back((*source)->GetFullPath());
}
else if(cmSystemTools::UpperCase((*source)->GetExtension()) == "DEF")
{
this->ModuleDefinitionFile = (*source)->GetFullPath();
}
else
{
// We only get here if a source file is not an external object
// and has an extension that is listed as an ignored file type
// for this language. No message or diagnosis should be
// given.
this->CleanFiles.push_back
(this->Convert(o->c_str(),
cmLocalGenerator::START_OUTPUT,
cmLocalGenerator::UNCHANGED));
}
}
}
for(std::vector<cmSourceFile*>::const_iterator
si = this->GeneratorTarget->OSXContent.begin();
si != this->GeneratorTarget->OSXContent.end(); ++si)
{
cmTarget::SourceFileFlags tsFlags =
this->Target->GetTargetSourceFileFlags(*si);
this->WriteMacOSXContentRules(**si, tsFlags.MacFolder);
}
for(std::vector<cmSourceFile*>::const_iterator
si = this->GeneratorTarget->ExternalObjects.begin();
si != this->GeneratorTarget->ExternalObjects.end(); ++si)
{
this->ExternalObjects.push_back((*si)->GetFullPath());
}
for(std::vector<cmSourceFile*>::const_iterator
si = this->GeneratorTarget->ObjectSources.begin();
si != this->GeneratorTarget->ObjectSources.end(); ++si)
{
// Generate this object file's rule file.
this->WriteObjectRuleFiles(**si);
}
// Add object library contents as external objects.
this->GeneratorTarget->UseObjectLibraries(this->ExternalObjects);
}
@ -428,12 +422,10 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(cmSourceFile& source)
}
// Get the full path name of the object file.
bool hasSourceExtension;
std::string objNoTargetDir;
std::string obj =
this->LocalGenerator->GetObjectFileName(*this->Target, source,
&objNoTargetDir,
&hasSourceExtension);
std::string const& objectName = this->GeneratorTarget->Objects[&source];
std::string obj = this->LocalGenerator->GetTargetDirectory(*this->Target);
obj += "/";
obj += objectName;
// Avoid generating duplicate rules.
if(this->ObjectFiles.find(obj) == this->ObjectFiles.end())
@ -487,10 +479,6 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(cmSourceFile& source)
AddImplicitDepends(*this->Target, lang,
objFullPath.c_str(),
srcFullPath.c_str());
// add this to the list of objects for this local generator
this->LocalGenerator->AddLocalObjectFile(
this->Target, &source, objNoTargetDir, hasSourceExtension);
}
//----------------------------------------------------------------------------
@ -1612,7 +1600,7 @@ void cmMakefileTargetGenerator
//----------------------------------------------------------------------------
void cmMakefileTargetGenerator
::AppendLinkDepends(std::vector<std::string>& depends)
::AppendObjectDepends(std::vector<std::string>& depends)
{
// Add dependencies on the compiled object files.
std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath();
@ -1625,19 +1613,6 @@ void cmMakefileTargetGenerator
depends.push_back(objTarget);
}
// Add dependencies on targets that must be built first.
this->AppendTargetDepends(depends);
// Add a dependency on the rule file itself.
this->LocalGenerator->AppendRuleDepend(depends,
this->BuildFileNameFull.c_str());
// Add a dependency on the link definitions file, if any.
if(!this->ModuleDefinitionFile.empty())
{
depends.push_back(this->ModuleDefinitionFile);
}
// Add dependencies on the external object files.
for(std::vector<std::string>::const_iterator obj
= this->ExternalObjects.begin();
@ -1646,6 +1621,26 @@ void cmMakefileTargetGenerator
depends.push_back(*obj);
}
// Add a dependency on the rule file itself.
this->LocalGenerator->AppendRuleDepend(depends,
this->BuildFileNameFull.c_str());
}
//----------------------------------------------------------------------------
void cmMakefileTargetGenerator
::AppendLinkDepends(std::vector<std::string>& depends)
{
this->AppendObjectDepends(depends);
// Add dependencies on targets that must be built first.
this->AppendTargetDepends(depends);
// Add a dependency on the link definitions file, if any.
if(!this->GeneratorTarget->ModuleDefinitionFile.empty())
{
depends.push_back(this->GeneratorTarget->ModuleDefinitionFile);
}
// Add user-specified dependencies.
if(const char* linkDepends =
this->Target->GetProperty("LINK_DEPENDS"))
@ -1971,7 +1966,7 @@ void cmMakefileTargetGenerator::AddFortranFlags(std::string& flags)
//----------------------------------------------------------------------------
void cmMakefileTargetGenerator::AddModuleDefinitionFlag(std::string& flags)
{
if(this->ModuleDefinitionFile.empty())
if(this->GeneratorTarget->ModuleDefinitionFile.empty())
{
return;
}
@ -1988,7 +1983,7 @@ void cmMakefileTargetGenerator::AddModuleDefinitionFlag(std::string& flags)
// vs6's "cl -link" pass it to the linker.
std::string flag = defFileFlag;
flag += (this->LocalGenerator->ConvertToLinkReference(
this->ModuleDefinitionFile.c_str()));
this->GeneratorTarget->ModuleDefinitionFile.c_str()));
this->LocalGenerator->AppendFlags(flags, flag.c_str());
}

View File

@ -17,6 +17,7 @@
class cmCustomCommand;
class cmDependInformation;
class cmDepends;
class cmGeneratorTarget;
class cmGeneratedFileStream;
class cmGlobalUnixMakefileGenerator3;
class cmLocalUnixMakefileGenerator3;
@ -117,6 +118,9 @@ protected:
// append intertarget dependencies
void AppendTargetDepends(std::vector<std::string>& depends);
// Append object file dependencies.
void AppendObjectDepends(std::vector<std::string>& depends);
// Append link rule dependencies (objects, etc.).
void AppendLinkDepends(std::vector<std::string>& depends);
@ -157,6 +161,7 @@ protected:
void RemoveForbiddenFlags(const char* flagVar, const char* linkLang,
std::string& linkFlags);
cmTarget *Target;
cmGeneratorTarget* GeneratorTarget;
cmLocalUnixMakefileGenerator3 *LocalGenerator;
cmGlobalUnixMakefileGenerator3 *GlobalGenerator;
cmMakefile *Makefile;
@ -198,9 +203,6 @@ protected:
std::vector<std::string> Objects;
std::vector<std::string> ExternalObjects;
// The windows module definition source file (.def), if any.
std::string ModuleDefinitionFile;
// Set of object file names that will be built in this directory.
std::set<cmStdString> ObjectFiles;

View File

@ -43,10 +43,13 @@ cmNinjaNormalTargetGenerator(cmTarget* target)
this->TargetNamePDB,
GetLocalGenerator()->GetConfigName());
// on Windows the output dir is already needed at compile time
// ensure the directory exists (OutDir test)
std::string outpath = target->GetDirectory(this->GetConfigName());
cmSystemTools::MakeDirectory(outpath.c_str());
if(target->GetType() != cmTarget::OBJECT_LIBRARY)
{
// on Windows the output dir is already needed at compile time
// ensure the directory exists (OutDir test)
std::string outpath = target->GetDirectory(this->GetConfigName());
cmSystemTools::MakeDirectory(outpath.c_str());
}
}
cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator()
@ -67,8 +70,15 @@ void cmNinjaNormalTargetGenerator::Generate()
// Write the build statements
this->WriteObjectBuildStatements();
this->WriteLinkRule();
this->WriteLinkStatement();
if(this->GetTarget()->GetType() == cmTarget::OBJECT_LIBRARY)
{
this->WriteObjectLibStatement();
}
else
{
this->WriteLinkRule();
this->WriteLinkStatement();
}
this->GetBuildFileStream() << "\n";
this->GetRulesFileStream() << "\n";
@ -467,3 +477,21 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
this->GetTarget());
}
//----------------------------------------------------------------------------
void cmNinjaNormalTargetGenerator::WriteObjectLibStatement()
{
// Write a phony output that depends on all object files.
cmNinjaDeps outputs;
this->GetLocalGenerator()->AppendTargetOutputs(this->GetTarget(), outputs);
cmNinjaDeps depends = this->GetObjects();
cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
"Object library "
+ this->GetTargetName(),
outputs,
depends);
// Add aliases for the target name.
this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
this->GetTarget());
}

View File

@ -32,6 +32,7 @@ private:
void WriteLanguagesRules();
void WriteLinkRule();
void WriteLinkStatement();
void WriteObjectLibStatement();
std::vector<std::string> ComputeLinkCmd();
private:

View File

@ -14,6 +14,7 @@
#include "cmGlobalNinjaGenerator.h"
#include "cmLocalNinjaGenerator.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmNinjaNormalTargetGenerator.h"
#include "cmNinjaUtilityTargetGenerator.h"
#include "cmSystemTools.h"
@ -33,6 +34,7 @@ cmNinjaTargetGenerator::New(cmTarget* target)
case cmTarget::SHARED_LIBRARY:
case cmTarget::STATIC_LIBRARY:
case cmTarget::MODULE_LIBRARY:
case cmTarget::OBJECT_LIBRARY:
return new cmNinjaNormalTargetGenerator(target);
case cmTarget::UTILITY:
@ -60,6 +62,8 @@ cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmTarget* target)
static_cast<cmLocalNinjaGenerator*>(Makefile->GetLocalGenerator())),
Objects()
{
this->GeneratorTarget =
this->GetGlobalGenerator()->GetGeneratorTarget(target);
}
cmNinjaTargetGenerator::~cmNinjaTargetGenerator()
@ -218,7 +222,8 @@ ComputeDefines(cmSourceFile *source, const std::string& language)
cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const
{
// Static libraries never depend on other targets for linking.
if (this->Target->GetType() == cmTarget::STATIC_LIBRARY)
if (this->Target->GetType() == cmTarget::STATIC_LIBRARY ||
this->Target->GetType() == cmTarget::OBJECT_LIBRARY)
return cmNinjaDeps();
cmComputeLinkInformation* cli =
@ -231,9 +236,9 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const
std::transform(deps.begin(), deps.end(), result.begin(), MapToNinjaPath());
// Add a dependency on the link definitions file, if any.
if(!this->ModuleDefinitionFile.empty())
if(!this->GeneratorTarget->ModuleDefinitionFile.empty())
{
result.push_back(this->ModuleDefinitionFile);
result.push_back(this->GeneratorTarget->ModuleDefinitionFile);
}
return result;
@ -253,7 +258,10 @@ cmNinjaTargetGenerator
std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
if(!path.empty())
path += "/";
path += this->LocalGenerator->GetObjectFileName(*this->Target, *source);
std::string const& objectName = this->GeneratorTarget->Objects[source];
path += this->LocalGenerator->GetTargetDirectory(*this->Target);
path += "/";
path += objectName;
return path;
}
@ -377,12 +385,37 @@ cmNinjaTargetGenerator
<< this->GetTargetName()
<< "\n\n";
// For each source files of this target.
for(std::vector<cmSourceFile*>::const_iterator i =
this->GetTarget()->GetSourceFiles().begin();
i != this->GetTarget()->GetSourceFiles().end();
++i)
this->WriteObjectBuildStatement(*i);
for(std::vector<cmSourceFile*>::const_iterator
si = this->GeneratorTarget->CustomCommands.begin();
si != this->GeneratorTarget->CustomCommands.end(); ++si)
{
cmCustomCommand const* cc = (*si)->GetCustomCommand();
this->GetLocalGenerator()->AddCustomCommandTarget(cc, this->GetTarget());
}
// TODO: this->GeneratorTarget->OSXContent
for(std::vector<cmSourceFile*>::const_iterator
si = this->GeneratorTarget->ExternalObjects.begin();
si != this->GeneratorTarget->ExternalObjects.end(); ++si)
{
this->Objects.push_back(this->GetSourceFilePath(*si));
}
for(std::vector<cmSourceFile*>::const_iterator
si = this->GeneratorTarget->ObjectSources.begin();
si != this->GeneratorTarget->ObjectSources.end(); ++si)
{
this->WriteObjectBuildStatement(*si);
}
{
// Add object library contents as external objects.
std::vector<std::string> objs;
this->GeneratorTarget->UseObjectLibraries(objs);
for(std::vector<std::string>::iterator oi = objs.begin();
oi != objs.end(); ++oi)
{
this->Objects.push_back(ConvertToNinjaPath(oi->c_str()));
}
}
this->GetBuildFileStream() << "\n";
}
@ -391,26 +424,10 @@ void
cmNinjaTargetGenerator
::WriteObjectBuildStatement(cmSourceFile* source)
{
if (cmCustomCommand *cc = source->GetCustomCommand())
this->GetLocalGenerator()->AddCustomCommandTarget(cc, this->GetTarget());
cmNinjaDeps emptyDeps;
std::string comment;
const char* language = source->GetLanguage();
// If we cannot get the language this is probably a non-source file provided
// in the list (typically an header file).
if (!language) {
if (source->GetPropertyAsBool("EXTERNAL_OBJECT"))
this->Objects.push_back(this->GetSourceFilePath(source));
if(cmSystemTools::UpperCase(source->GetExtension()) == "DEF")
this->ModuleDefinitionFile = GetSourceFilePath(source);
return;
}
if (source->GetPropertyAsBool("HEADER_FILE_ONLY"))
return;
std::string rule = this->LanguageCompilerRule(language);
cmNinjaDeps outputs;
@ -435,21 +452,16 @@ cmNinjaTargetGenerator
std::back_inserter(orderOnlyDeps), MapToNinjaPath());
}
// Add order-only dependency on any header file with a custom command.
{
const std::vector<cmSourceFile*>& sources =
this->GetTarget()->GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator si = sources.begin();
si != sources.end(); ++si) {
if (!(*si)->GetLanguage()) {
if (cmCustomCommand* cc = (*si)->GetCustomCommand()) {
const std::vector<std::string>& ccoutputs = cc->GetOutputs();
std::transform(ccoutputs.begin(), ccoutputs.end(),
std::back_inserter(orderOnlyDeps), MapToNinjaPath());
}
}
// Add order-only dependencies on custom command outputs.
for(std::vector<cmSourceFile*>::const_iterator
si = this->GeneratorTarget->CustomCommands.begin();
si != this->GeneratorTarget->CustomCommands.end(); ++si)
{
cmCustomCommand const* cc = (*si)->GetCustomCommand();
const std::vector<std::string>& ccoutputs = cc->GetOutputs();
std::transform(ccoutputs.begin(), ccoutputs.end(),
std::back_inserter(orderOnlyDeps), MapToNinjaPath());
}
}
// If the source file is GENERATED and does not have a custom command
// (either attached to this source file or another one), assume that one of
@ -493,7 +505,7 @@ void
cmNinjaTargetGenerator
::AddModuleDefinitionFlag(std::string& flags)
{
if(this->ModuleDefinitionFile.empty())
if(this->GeneratorTarget->ModuleDefinitionFile.empty())
{
return;
}
@ -510,6 +522,6 @@ cmNinjaTargetGenerator
// vs6's "cl -link" pass it to the linker.
std::string flag = defFileFlag;
flag += (this->LocalGenerator->ConvertToLinkReference(
this->ModuleDefinitionFile.c_str()));
this->GeneratorTarget->ModuleDefinitionFile.c_str()));
this->LocalGenerator->AppendFlags(flags, flag.c_str());
}

View File

@ -20,6 +20,7 @@
class cmTarget;
class cmGlobalNinjaGenerator;
class cmGeneratedFileStream;
class cmGeneratorTarget;
class cmMakefile;
class cmSourceFile;
class cmCustomCommand;
@ -112,13 +113,11 @@ protected:
private:
cmTarget* Target;
cmGeneratorTarget* GeneratorTarget;
cmMakefile* Makefile;
cmLocalNinjaGenerator* LocalGenerator;
/// List of object files for this target.
cmNinjaDeps Objects;
// The windows module definition source file (.def), if any.
std::string ModuleDefinitionFile;
};
#endif // ! cmNinjaTargetGenerator_h

View File

@ -119,12 +119,6 @@ const std::vector<const cmSourceFile*>& cmSourceGroup::GetSourceFiles() const
return this->SourceFiles;
}
//----------------------------------------------------------------------------
std::vector<const cmSourceFile*>& cmSourceGroup::GetSourceFiles()
{
return this->SourceFiles;
}
//----------------------------------------------------------------------------
void cmSourceGroup::AddChild(cmSourceGroup child)
{

View File

@ -100,7 +100,6 @@ public:
* source group.
*/
const std::vector<const cmSourceFile*>& GetSourceFiles() const;
std::vector<const cmSourceFile*>& GetSourceFiles();
std::vector<cmSourceGroup> const& GetGroupChildren() const;
private:

View File

@ -37,6 +37,8 @@ const char* cmTarget::GetTargetTypeName(TargetType targetType)
return "MODULE_LIBRARY";
case cmTarget::SHARED_LIBRARY:
return "SHARED_LIBRARY";
case cmTarget::OBJECT_LIBRARY:
return "OBJECT_LIBRARY";
case cmTarget::EXECUTABLE:
return "EXECUTABLE";
case cmTarget::UTILITY:
@ -1727,7 +1729,15 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs)
for(std::vector<std::string>::const_iterator i = srcs.begin();
i != srcs.end(); ++i)
{
this->AddSource(i->c_str());
const char* src = i->c_str();
if(src[0] == '$' && src[1] == '<')
{
this->ProcessSourceExpression(*i);
}
else
{
this->AddSource(src);
}
}
}
@ -1745,6 +1755,24 @@ cmSourceFile* cmTarget::AddSource(const char* s)
return sf;
}
//----------------------------------------------------------------------------
void cmTarget::ProcessSourceExpression(std::string const& expr)
{
if(strncmp(expr.c_str(), "$<TARGET_OBJECTS:", 17) == 0 &&
expr[expr.size()-1] == '>')
{
std::string objLibName = expr.substr(17, expr.size()-18);
this->ObjectLibraries.push_back(objLibName);
}
else
{
cmOStringStream e;
e << "Unrecognized generator expression:\n"
<< " " << expr;
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
}
}
//----------------------------------------------------------------------------
struct cmTarget::SourceFileFlags
cmTarget::GetTargetSourceFileFlags(const cmSourceFile* sf)
@ -4545,7 +4573,21 @@ void cmTarget::ComputeLinkImplementation(const char* config,
// This target needs runtime libraries for its source languages.
std::set<cmStdString> languages;
// Get languages used in our source files.
this->GetLanguages(languages);
// Get languages used in object library sources.
for(std::vector<std::string>::iterator i = this->ObjectLibraries.begin();
i != this->ObjectLibraries.end(); ++i)
{
if(cmTarget* objLib = this->Makefile->FindTargetToUse(i->c_str()))
{
if(objLib->GetType() == cmTarget::OBJECT_LIBRARY)
{
objLib->GetLanguages(languages);
}
}
}
// Copy the set of langauges to the link implementation.
for(std::set<cmStdString>::iterator li = languages.begin();
li != languages.end(); ++li)
{

View File

@ -59,7 +59,8 @@ class cmTarget
public:
cmTarget();
enum TargetType { EXECUTABLE, STATIC_LIBRARY,
SHARED_LIBRARY, MODULE_LIBRARY, UTILITY, GLOBAL_TARGET,
SHARED_LIBRARY, MODULE_LIBRARY,
OBJECT_LIBRARY, UTILITY, GLOBAL_TARGET,
UNKNOWN_LIBRARY};
static const char* GetTargetTypeName(TargetType targetType);
enum CustomCommandType { PRE_BUILD, PRE_LINK, POST_BUILD };
@ -116,6 +117,10 @@ public:
*/
std::vector<cmSourceFile*> const& GetSourceFiles();
void AddSourceFile(cmSourceFile* sf);
std::vector<std::string> const& GetObjectLibraries() const
{
return this->ObjectLibraries;
}
/** Get sources that must be built before the given source. */
std::vector<cmSourceFile*> const* GetSourceDepends(cmSourceFile* sf);
@ -548,6 +553,7 @@ private:
std::vector<cmCustomCommand> PostBuildCommands;
TargetType TargetTypeValue;
std::vector<cmSourceFile*> SourceFiles;
std::vector<std::string> ObjectLibraries;
LinkLibraryVectorType LinkLibraries;
LinkLibraryVectorType PrevLinkedLibraries;
bool LinkLibrariesAnalyzed;
@ -589,6 +595,8 @@ private:
void MaybeInvalidatePropertyCache(const char* prop);
void ProcessSourceExpression(std::string const& expr);
// The cmMakefile instance that owns this target. This should
// always be set.
cmMakefile* Makefile;

View File

@ -84,6 +84,16 @@ bool cmTargetLinkLibrariesCommand
return true;
}
if(this->Target->GetType() == cmTarget::OBJECT_LIBRARY)
{
cmOStringStream e;
e << "Object library target \"" << args[0] << "\" "
<< "may not link to anything.";
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
cmSystemTools::SetFatalErrorOccured();
return true;
}
// but we might not have any libs after variable expansion
if(args.size() < 2)
{

View File

@ -11,6 +11,7 @@
============================================================================*/
#include "cmVisualStudio10TargetGenerator.h"
#include "cmGlobalVisualStudio10Generator.h"
#include "cmGeneratorTarget.h"
#include "cmTarget.h"
#include "cmComputeLinkInformation.h"
#include "cmGeneratedFileStream.h"
@ -62,6 +63,7 @@ cmVisualStudio10TargetGenerator(cmTarget* target,
{
this->GlobalGenerator = gg;
this->Target = target;
this->GeneratorTarget = gg->GetGeneratorTarget(target);
this->Makefile = target->GetMakefile();
this->LocalGenerator =
(cmLocalVisualStudio7Generator*)
@ -70,7 +72,6 @@ cmVisualStudio10TargetGenerator(cmTarget* target,
this->GlobalGenerator->CreateGUID(this->Name.c_str());
this->GUID = this->GlobalGenerator->GetGUID(this->Name.c_str());
this->Platform = gg->GetPlatformName();
this->ComputeObjectNames();
this->BuildFileStream = 0;
}
@ -147,7 +148,7 @@ void cmVisualStudio10TargetGenerator::Generate()
this->Target->SetProperty("GENERATOR_FILE_NAME",this->Name.c_str());
this->Target->SetProperty("GENERATOR_FILE_NAME_EXT",
".vcxproj");
if(this->Target->GetType() <= cmTarget::MODULE_LIBRARY)
if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY)
{
if(!this->ComputeClOptions())
{
@ -358,6 +359,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
case cmTarget::MODULE_LIBRARY:
configType += "DynamicLibrary";
break;
case cmTarget::OBJECT_LIBRARY:
case cmTarget::STATIC_LIBRARY:
configType += "StaticLibrary";
break;
@ -388,7 +390,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
mfcLine += useOfMfcValue + "</UseOfMfc>\n";
this->WriteString(mfcLine.c_str(), 2);
if(this->Target->GetType() <= cmTarget::MODULE_LIBRARY &&
if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY &&
this->ClOptions[*i]->UsingUnicode() ||
this->Target->GetPropertyAsBool("VS_WINRT_EXTENSIONS"))
{
@ -421,12 +423,11 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
void cmVisualStudio10TargetGenerator::WriteCustomCommands()
{
this->SourcesVisited.clear();
std::vector<cmSourceFile*> const& sources = this->Target->GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
source != sources.end(); ++source)
for(std::vector<cmSourceFile*>::const_iterator
si = this->GeneratorTarget->CustomCommands.begin();
si != this->GeneratorTarget->CustomCommands.end(); ++si)
{
cmSourceFile* sf = *source;
this->WriteCustomCommand(sf);
this->WriteCustomCommand(*si);
}
}
@ -634,6 +635,25 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
this->WriteGroupSources("Midl", idls, sourceGroups);
this->WriteGroupSources("CustomBuild", customBuild, sourceGroups);
// Add object library contents as external objects.
std::vector<std::string> objs;
this->GeneratorTarget->UseObjectLibraries(objs);
if(!objs.empty())
{
this->WriteString("<ItemGroup>\n", 1);
for(std::vector<std::string>::const_iterator
oi = objs.begin(); oi != objs.end(); ++oi)
{
std::string obj = *oi;
this->WriteString("<Object Include=\"", 2);
this->ConvertToWindowsSlash(obj);
(*this->BuildFileStream ) << obj << "\">\n";
this->WriteString("<Filter>Object Libraries</Filter>\n", 3);
this->WriteString("</Object>\n", 2);
}
this->WriteString("</ItemGroup>\n", 1);
}
this->WriteString("<ItemGroup>\n", 1);
for(std::set<cmSourceGroup*>::iterator g = groupsUsed.begin();
g != groupsUsed.end(); ++g)
@ -657,6 +677,18 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
this->WriteString("</Filter>\n", 2);
}
}
if(!objs.empty())
{
this->WriteString("<Filter Include=\"Object Libraries\">\n", 2);
std::string guidName = "SG_Filter_Object Libraries";
this->GlobalGenerator->CreateGUID(guidName.c_str());
this->WriteString("<UniqueIdentifier>", 3);
std::string guid =
this->GlobalGenerator->GetGUID(guidName.c_str());
(*this->BuildFileStream) << "{" << guid << "}"
<< "</UniqueIdentifier>\n";
this->WriteString("</Filter>\n", 2);
}
this->WriteString("</ItemGroup>\n", 1);
this->WriteGroupSources("None", none, sourceGroups);
this->WriteString("</Project>\n", 0);
@ -872,26 +904,20 @@ void cmVisualStudio10TargetGenerator::WriteCLSources()
(*this->BuildFileStream ) << " />\n";
}
}
this->WriteString("</ItemGroup>\n", 1);
}
void cmVisualStudio10TargetGenerator::ComputeObjectNames()
{
// get the classes from the source lists then add them to the groups
std::vector<cmSourceFile*>const & classes = this->Target->GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
i != classes.end(); i++)
// Add object library contents as external objects.
std::vector<std::string> objs;
this->GeneratorTarget->UseObjectLibraries(objs);
for(std::vector<std::string>::const_iterator
oi = objs.begin(); oi != objs.end(); ++oi)
{
// Add the file to the list of sources.
std::string source = (*i)->GetFullPath();
if(cmSystemTools::UpperCase((*i)->GetExtension()) == "DEF")
{
this->ModuleDefinitionFile = (*i)->GetFullPath();
}
std::string obj = *oi;
this->WriteString("<Object Include=\"", 2);
this->ConvertToWindowsSlash(obj);
(*this->BuildFileStream ) << obj << "\" />\n";
}
// Compute which sources need unique object computation.
this->LocalGenerator->ComputeObjectNameRequirements(classes);
this->WriteString("</ItemGroup>\n", 1);
}
bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
@ -900,16 +926,11 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
cmSourceFile& sf = *source;
cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
// Compute the maximum length full path to the intermediate
// files directory for any configuration. This is used to construct
// object file names that do not produce paths that are too long.
std::string dir_max;
lg->ComputeMaxDirectoryLength(dir_max, *this->Target);
std::string objectName;
if(lg->NeedObjectName.find(&sf) != lg->NeedObjectName.end())
if(this->GeneratorTarget->ExplicitObjectName.find(&sf)
!= this->GeneratorTarget->ExplicitObjectName.end())
{
objectName = lg->GetObjectFileNameWithoutTarget(sf, dir_max);
objectName = this->GeneratorTarget->Objects[&sf];
}
std::string flags;
std::string defines;
@ -1030,20 +1051,29 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions()
}
else
{
std::string targetNameFull =
this->Target->GetFullName(config->c_str());
std::string intermediateDir = this->LocalGenerator->
GetTargetDirectory(*this->Target);
intermediateDir += "/";
intermediateDir += *config;
intermediateDir += "/";
std::string outDir;
std::string targetNameFull;
if(ttype == cmTarget::OBJECT_LIBRARY)
{
outDir = intermediateDir;
targetNameFull = this->Target->GetName();
targetNameFull += ".lib";
}
else
{
outDir = this->Target->GetDirectory(config->c_str()) + "/";
targetNameFull = this->Target->GetFullName(config->c_str());
}
this->ConvertToWindowsSlash(intermediateDir);
std::string outDir = this->Target->GetDirectory(config->c_str());
this->ConvertToWindowsSlash(outDir);
this->WritePlatformConfigTag("OutDir", config->c_str(), 3);
*this->BuildFileStream << outDir
<< "\\"
<< "</OutDir>\n";
this->WritePlatformConfigTag("IntDir", config->c_str(), 3);
@ -1277,11 +1307,15 @@ void cmVisualStudio10TargetGenerator::WriteClOptions(
*this->BuildFileStream << configName
<< "</AssemblerListingLocation>\n";
this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3);
this->WriteString("<ProgramDataBaseFileName>", 3);
*this->BuildFileStream << this->Target->GetDirectory(configName.c_str())
<< "/"
<< this->Target->GetPDBName(configName.c_str())
<< "</ProgramDataBaseFileName>\n";
if(this->Target->GetType() != cmTarget::OBJECT_LIBRARY)
{
// TODO: PDB for object library?
this->WriteString("<ProgramDataBaseFileName>", 3);
*this->BuildFileStream << this->Target->GetDirectory(configName.c_str())
<< "/"
<< this->Target->GetPDBName(configName.c_str())
<< "</ProgramDataBaseFileName>\n";
}
this->WriteString("</ClCompile>\n", 2);
}
@ -1513,10 +1547,10 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions(std::string const&
linkOptions.AddFlag("ImportLibrary", imLib.c_str());
linkOptions.AddFlag("ProgramDataBaseFile", pdb.c_str());
linkOptions.Parse(flags.c_str());
if(!this->ModuleDefinitionFile.empty())
if(!this->GeneratorTarget->ModuleDefinitionFile.empty())
{
linkOptions.AddFlag("ModuleDefinitionFile",
this->ModuleDefinitionFile.c_str());
this->GeneratorTarget->ModuleDefinitionFile.c_str());
}
linkOptions.RemoveFlag("GenerateManifest");
@ -1592,7 +1626,7 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups()
this->WritePlatformConfigTag("ItemDefinitionGroup", i->c_str(), 1);
*this->BuildFileStream << "\n";
// output cl compile flags <ClCompile></ClCompile>
if(this->Target->GetType() <= cmTarget::MODULE_LIBRARY)
if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY)
{
this->WriteClOptions(*i, includes);
// output rc compile flags <ResourceCompile></ResourceCompile>

View File

@ -15,6 +15,7 @@
class cmTarget;
class cmMakefile;
class cmGeneratorTarget;
class cmGeneratedFileStream;
class cmGlobalVisualStudio10Generator;
class cmSourceFile;
@ -75,7 +76,6 @@ private:
void WriteEvents(std::string const& configName);
void WriteEvent(const char* name, std::vector<cmCustomCommand> & commands,
std::string const& configName);
void ComputeObjectNames();
void WriteGroupSources(const char* name,
std::vector<cmSourceFile*> const& sources,
std::vector<cmSourceGroup>& );
@ -87,9 +87,9 @@ private:
typedef cmVisualStudioGeneratorOptions Options;
typedef std::map<cmStdString, Options*> OptionsMap;
OptionsMap ClOptions;
std::string ModuleDefinitionFile;
std::string PathToVcxproj;
cmTarget* Target;
cmGeneratorTarget* GeneratorTarget;
cmMakefile* Makefile;
std::string Platform;
std::string GUID;

View File

@ -199,6 +199,7 @@ IF(BUILD_TESTING)
ADD_TEST_MACRO(CxxOnly CxxOnly)
ADD_TEST_MACRO(IPO COnly/COnly)
ADD_TEST_MACRO(OutDir runtime/OutDir)
ADD_TEST_MACRO(ObjectLibrary UseCshared)
ADD_TEST_MACRO(NewlineArgs NewlineArgs)
ADD_TEST_MACRO(SetLang SetLang)
ADD_TEST_MACRO(ExternalOBJ ExternalOBJ)

View File

@ -0,0 +1,17 @@
# Add -fPIC so objects can be used in shared libraries.
# TODO: Need property for this.
if(CMAKE_SHARED_LIBRARY_C_FLAGS)
set(CMAKE_C_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS} ${CMAKE_C_FLAGS}")
endif()
add_definitions(-DA)
add_custom_command(
OUTPUT a1.c
DEPENDS a1.c.in
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/a1.c.in
${CMAKE_CURRENT_BINARY_DIR}/a1.c
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_library(A OBJECT a1.c a2.c)

View File

@ -0,0 +1,6 @@
#ifndef A
# error "A not defined"
#endif
#ifdef B
# error "B must not be defined"
#endif

View File

@ -0,0 +1,2 @@
#include "a.h"
int a1(void) { return 0; }

View File

@ -0,0 +1,2 @@
#include "a.h"
int a2(void) { return 0; }

View File

@ -0,0 +1,5 @@
EXPORTS
a1
a2
b1
b2

View File

@ -0,0 +1,15 @@
if("${CMAKE_GENERATOR}" MATCHES "Visual Studio 6")
# VS 6 generator does not use per-target object locations.
set(vs6 _vs6)
endif()
# Add -fPIC so objects can be used in shared libraries.
# TODO: Need property for this.
if(CMAKE_SHARED_LIBRARY_C_FLAGS)
set(CMAKE_C_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS} ${CMAKE_C_FLAGS}")
endif()
add_definitions(-DB)
add_library(B OBJECT b1.c b2.c)
add_library(Bexport OBJECT b1${vs6}.c b2${vs6}.c)
set_property(TARGET Bexport PROPERTY COMPILE_DEFINITIONS Bexport)

11
Tests/ObjectLibrary/B/b.h Normal file
View File

@ -0,0 +1,11 @@
#ifdef A
# error "A must not be defined"
#endif
#ifndef B
# error "B not defined"
#endif
#if defined(_WIN32) && defined(Bexport)
# define EXPORT_B __declspec(dllexport)
#else
# define EXPORT_B
#endif

View File

@ -0,0 +1,2 @@
#include "b.h"
EXPORT_B int b1(void) { return 0; }

View File

@ -0,0 +1 @@
#include "b1.c"

View File

@ -0,0 +1,2 @@
#include "b.h"
EXPORT_B int b2(void) { return 0; }

View File

@ -0,0 +1 @@
#include "b2.c"

View File

@ -0,0 +1,52 @@
cmake_minimum_required(VERSION 2.8)
project(ObjectLibrary C)
add_subdirectory(A)
add_subdirectory(B)
add_library(Cstatic STATIC c.c $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>)
add_executable(UseCstatic main.c)
target_link_libraries(UseCstatic Cstatic)
add_library(Cshared SHARED c.c $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:Bexport>)
add_executable(UseCshared main.c)
set_property(TARGET UseCshared PROPERTY COMPILE_DEFINITIONS SHARED_C)
target_link_libraries(UseCshared Cshared)
add_executable(UseCinternal main.c c.c $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>)
if("${CMAKE_GENERATOR}" MATCHES "^Visual Studio (6|7|7 .NET 2003)$")
# VS 6 and 7 generators do not add objects as sources so we need a
# dummy object to convince the IDE to build the targets below.
set(dummy dummy.obj) # In MinGW: gcc -c dummy.c -o dummy.obj
elseif("${CMAKE_GENERATOR}" MATCHES "Xcode")
# Xcode does not seem to support targets without sources.
set(dummy dummy.c)
endif()
# Test static library without its own sources.
add_library(ABstatic STATIC ${dummy} $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>)
add_executable(UseABstatic mainAB.c)
target_link_libraries(UseABstatic ABstatic)
# Test module definition file to export object library symbols in the test
# below if the platform needs and supports it.
set(ABshared_SRCS $<TARGET_OBJECTS:A>)
if(CMAKE_LINK_DEF_FILE_FLAG OR NOT WIN32)
list(APPEND ABshared_SRCS $<TARGET_OBJECTS:B> AB.def)
else()
set(NO_A NO_A)
list(APPEND ABshared_SRCS $<TARGET_OBJECTS:Bexport>)
endif()
# Test shared library without its own sources.
add_library(ABshared SHARED ${dummy} ${ABshared_SRCS})
add_executable(UseABshared mainAB.c)
set_property(TARGET UseABshared PROPERTY COMPILE_DEFINITIONS SHARED_B ${NO_A})
target_link_libraries(UseABshared ABshared)
# Test executable without its own sources.
add_library(ABmain OBJECT mainAB.c)
add_executable(UseABinternal ${dummy}
$<TARGET_OBJECTS:ABmain> $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>
)

19
Tests/ObjectLibrary/c.c Normal file
View File

@ -0,0 +1,19 @@
#if defined(_WIN32) && defined(Cshared_EXPORTS)
# define EXPORT_C __declspec(dllexport)
#else
# define EXPORT_C
#endif
extern int a1(void);
extern int a2(void);
extern int b1(void);
extern int b2(void);
EXPORT_C int c(void)
{
return 0
+ a1()
+ a2()
+ b1()
+ b2()
;
}

View File

@ -0,0 +1 @@
int dummy(void) {return 0;}

Binary file not shown.

View File

@ -0,0 +1,16 @@
#if defined(_WIN32) && defined(SHARED_C)
# define IMPORT_C __declspec(dllimport)
#else
# define IMPORT_C
#endif
extern IMPORT_C int b1(void);
extern IMPORT_C int b2(void);
extern IMPORT_C int c(void);
int main(void)
{
return 0
+ c()
+ b1()
+ b2()
;
}

View File

@ -0,0 +1,22 @@
#if defined(_WIN32) && defined(SHARED_B)
# define IMPORT_B __declspec(dllimport)
#else
# define IMPORT_B
#endif
extern IMPORT_B int b1(void);
extern IMPORT_B int b2(void);
#ifndef NO_A
extern int a1(void);
extern int a2(void);
#endif
int main(void)
{
return 0
#ifndef NO_A
+ a1()
+ a2()
#endif
+ b1()
+ b2()
;
}

View File

@ -40,5 +40,7 @@ macro(add_RunCMake_test test)
)
endmacro()
add_RunCMake_test(ObjectLibrary)
add_RunCMake_test(build_command)
add_RunCMake_test(find_package)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,8 @@
CMake Error at BadObjSource1.cmake:1 \(add_library\):
OBJECT library "A" contains:
bad.def
but may contain only headers and sources that compile.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1 @@
add_library(A OBJECT a.c bad.def)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,8 @@
CMake Error at BadObjSource2.cmake:1 \(add_library\):
OBJECT library "A" contains:
bad.obj
but may contain only headers and sources that compile.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1 @@
add_library(A OBJECT a.c bad.obj)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,6 @@
CMake Error at BadSourceExpression1.cmake:1 \(add_library\):
Unrecognized generator expression:
\$<BAD_EXPRESSION>
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1 @@
add_library(A STATIC a.c $<BAD_EXPRESSION>)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at BadSourceExpression2.cmake:1 \(add_library\):
Objects of target "DoesNotExist" referenced but no such target exists.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1 @@
add_library(A STATIC a.c $<TARGET_OBJECTS:DoesNotExist>)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at BadSourceExpression3.cmake:2 \(add_library\):
Objects of target "NotObjLib" referenced but is not an OBJECT library.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,2 @@
add_library(NotObjLib STATIC a.c)
add_library(A STATIC a.c $<TARGET_OBJECTS:NotObjLib>)

View File

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 2.8)
project(${RunCMake_TEST} C)
include(${RunCMake_TEST}.cmake)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at Export.cmake:2 \(export\):
export given OBJECT library "A" which may not be exported.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,2 @@
add_library(A OBJECT a.c)
export(TARGETS A FILE AExport.cmake)

View File

@ -0,0 +1,15 @@
enable_language(CXX)
add_library(A OBJECT a.cxx)
add_library(B STATIC a.c $<TARGET_OBJECTS:A>)
# Verify that object library languages are propagated.
export(TARGETS B NAMESPACE Exp FILE BExport.cmake)
include(${CMAKE_CURRENT_BINARY_DIR}/BExport.cmake)
get_property(configs TARGET ExpB PROPERTY IMPORTED_CONFIGURATIONS)
foreach(c ${configs})
get_property(langs TARGET ExpB PROPERTY IMPORTED_LINK_INTERFACE_LANGUAGES_${c})
list(FIND langs CXX pos)
if(${pos} LESS 0)
message(FATAL_ERROR "Target export does not list object library languages.")
endif()
endforeach()

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at Import.cmake:1 \(add_library\):
The OBJECT library type may not be used for IMPORTED libraries.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1 @@
add_library(A OBJECT IMPORTED)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at Install.cmake:2 \(install\):
install TARGETS given OBJECT library "A" which may not be installed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,2 @@
add_library(A OBJECT a.c)
install(TARGETS A DESTINATION lib)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at LinkObjLHS.cmake:2 \(target_link_libraries\):
Object library target "AnObjLib" may not link to anything.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,2 @@
add_library(AnObjLib OBJECT a.c)
target_link_libraries(AnObjLib OtherLib)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,6 @@
CMake Error at LinkObjRHS1.cmake:3 \(target_link_libraries\):
Target "AnObjLib" of type OBJECT_LIBRARY may not be linked into another
target. One may link only to STATIC or SHARED libraries, or to executables
with the ENABLE_EXPORTS property set.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,3 @@
add_library(A STATIC a.c)
add_library(AnObjLib OBJECT a.c)
target_link_libraries(A AnObjLib)

Some files were not shown because too many files have changed in this diff Show More