/*
* This file is part of Code::Blocks Studio, an open-source cross-platform IDE
* Copyright (C) 2003 Yiannis An. Mandravellos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact e-mail: Yiannis An. Mandravellos <mandrav@codeblocks.org>
* Program URL : http://www.codeblocks.org
*
* $Id: makefilegenerator.cpp,v 1.60.2.1 2005/10/25 07:59:01 mandrav Exp $
* $Date: 2005/10/25 07:59:01 $
*/
#include <sdk.h>
#include "makefilegenerator.h" // class's header file
#include <manager.h>
#include <macrosmanager.h>
#include <messagemanager.h>
#include <wx/file.h>
#include <compilerfactory.h>
#include <customvars.h>
// TODO (mandrav#1#): Fix Makefile for targets using different compilers
// class constructor
MakefileGenerator::MakefileGenerator(CompilerGCC* compiler, cbProject* project, const wxString& makefile, int logIndex)
: m_Compiler(compiler),
m_CompilerSet(CompilerFactory::Compilers[compiler->GetCurrentCompilerIndex()]),
m_Project(project),
m_Makefile(makefile),
m_LogIndex(logIndex),
m_GeneratingMakefile(false)
{
}
// class destructor
MakefileGenerator::~MakefileGenerator()
{
}
void MakefileGenerator::UpdateCompiler(ProjectBuildTarget* target)
{
int idx = target
? target->GetCompilerIndex()
: (m_Project ? m_Project->GetCompilerIndex() : -1);
if (idx != -1)
m_CompilerSet = CompilerFactory::Compilers[idx];
else
m_CompilerSet = CompilerFactory::GetDefaultCompiler();
}
wxString MakefileGenerator::ReplaceCompilerMacros(CommandType et,
const wxString& compilerVar,
ProjectBuildTarget* target,
const wxString& file,
const wxString& object,
const wxString& deps)
{
wxString compilerCmd;
UpdateCompiler(target);
compilerCmd = m_CompilerSet->GetCommand(et);
compilerCmd.Replace(_T("$compiler"), _T("$(") + target->GetTitle() + _T("_") + compilerVar + _T(")"));
compilerCmd.Replace(_T("$linker"), _T("$(") + target->GetTitle() + _T("_LD)"));
compilerCmd.Replace(_T("$lib_linker"), _T("$(") + target->GetTitle() + _T("_LIB)"));
compilerCmd.Replace(_T("$rescomp"), _T("$(") + target->GetTitle() + _T("_RESCOMP)"));
compilerCmd.Replace(_T("$options"), _T("$(") + target->GetTitle() + _T("_CFLAGS)"));
compilerCmd.Replace(_T("$link_options"), _T("$(") + target->GetTitle() + _T("_LDFLAGS)"));
compilerCmd.Replace(_T("$includes"), _T("$(") + target->GetTitle() + _T("_INCS)"));
compilerCmd.Replace(_T("$libdirs"), _T("$(") + target->GetTitle() + _T("_LIBDIRS)"));
compilerCmd.Replace(_T("$libs"), _T("$(") + target->GetTitle() + _T("_LIBS)"));
compilerCmd.Replace(_T("$file"), file);
compilerCmd.Replace(_T("$objects"), _T("$(") + target->GetTitle() + _T("_OBJS)"));
compilerCmd.Replace(_T("$dep_object"), deps);
compilerCmd.Replace(_T("$object"), object);
compilerCmd.Replace(_T("$link_objects"), _T("$(") + target->GetTitle() + _T("_LINKOBJS)"));
compilerCmd.Replace(_T("$link_resobjects"), _T("$(") + target->GetTitle() + _T("_RESOURCE)"));
compilerCmd.Replace(_T("$exe_output"), _T("$(") + target->GetTitle() + _T("_BIN)"));
if (target->GetTargetType() == ttStaticLib)
compilerCmd.Replace(_T("$static_output"), _T("$(") + target->GetTitle() + _T("_BIN)"));
else if (target->GetTargetType() == ttDynamicLib && target->GetCreateStaticLib())
compilerCmd.Replace(_T("$static_output"), _T("$(") + target->GetTitle() + _T("_STATIC_LIB)"));
else
compilerCmd.Replace(_T("-Wl,--out-implib=$static_output"), _T(""));
if (target->GetTargetType() == ttDynamicLib && target->GetCreateStaticLib())
compilerCmd.Replace(_T("$def_output"), _T("$(") + target->GetTitle() + _T("_LIB_DEF)"));
else
compilerCmd.Replace(_T("-Wl,--output-def=$def_output"), _T(""));
compilerCmd.Replace(_T("$resource_output"), _T("$(") + target->GetTitle() + _T("_RESOURCE)"));
int idx = compilerCmd.Find(_T("$res_includes"));
if (idx != -1)
{
wxString incs;
DoAppendResourceIncludeDirs(incs, 0L, m_CompilerSet->GetSwitches().includeDirs, true);
DoAppendResourceIncludeDirs(incs, 0L, m_CompilerSet->GetSwitches().includeDirs);
DoAppendResourceIncludeDirs(incs, target, m_CompilerSet->GetSwitches().includeDirs);
compilerCmd.Replace(_T("$res_includes"), incs);
}
return compilerCmd;
}
wxString MakefileGenerator::CreateSingleFileCompileCmd(CommandType et,
ProjectBuildTarget* target,
ProjectFile* pf,
const wxString& file,
const wxString& object,
const wxString& deps)
{
UpdateCompiler(target);
return CreateSingleFileCompileCmd(m_CompilerSet->GetCommand(et), target, pf, file, object, deps);
}
wxString MakefileGenerator::CreateSingleFileCompileCmd(const wxString& command,
ProjectBuildTarget* target,
ProjectFile* pf,
const wxString& file,
const wxString& object,
const wxString& deps)
{
// in case of linking command, deps has resource objects
UpdateCompiler(target);
wxString compilerStr;
if (pf)
{
if (pf->compilerVar.Matches(_T("CPP")))
compilerStr = m_CompilerSet->GetPrograms().CPP;
else if (pf->compilerVar.Matches(_T("CC")))
compilerStr = m_CompilerSet->GetPrograms().C;
else if (pf->compilerVar.Matches(_T("WINDRES")))
compilerStr = m_CompilerSet->GetPrograms().WINDRES;
else
return wxEmptyString; // unknown compiler var
}
else
{
wxFileName fname(file);
if (fname.GetExt().Lower().Matches(_T("c")))
compilerStr = m_CompilerSet->GetPrograms().C;
else
compilerStr = m_CompilerSet->GetPrograms().CPP;
}
wxString cflags;
wxString global_cflags;
wxString prj_cflags;
DoAppendCompilerOptions(global_cflags, 0L, true);
DoAppendCompilerOptions(prj_cflags, 0L);
DoGetMakefileCFlags(cflags, target);
if (target)
{
cflags.Replace(_T("$(") + target->GetTitle() + _T("_GLOBAL_CFLAGS)"), global_cflags);
cflags.Replace(_T("$(") + target->GetTitle() + _T("_PROJECT_CFLAGS)"), prj_cflags);
}
else if (!target && !pf) // probably single file compilation
cflags = global_cflags;
wxString ldflags;
wxString global_ldflags;
wxString prj_ldflags;
DoAppendLinkerOptions(global_ldflags, 0L, true);
DoAppendLinkerOptions(prj_ldflags, 0L);
DoGetMakefileLDFlags(ldflags, target);
if (target)
{
ldflags.Replace(_T("$(") + target->GetTitle() + _T("_GLOBAL_LDFLAGS)"), global_ldflags);
ldflags.Replace(_T("$(") + target->GetTitle() + _T("_PROJECT_LDFLAGS)"), prj_ldflags);
}
else if (!target && !pf) // probably single file compilation
ldflags = global_ldflags;
wxString ldadd;
wxString global_ldadd;
wxString prj_ldadd;
DoAppendLinkerLibs(global_ldadd, 0L, true);
DoAppendLinkerLibs(prj_ldadd, 0L);
DoGetMakefileLibs(ldadd, target);
if (target)
{
ldadd.Replace(_T("$(") + target->GetTitle() + _T("_GLOBAL_LIBS)"), global_ldadd);
ldadd.Replace(_T("$(") + target->GetTitle() + _T("_PROJECT_LIBS)"), prj_ldadd);
}
else if (!target && !pf) // probably single file compilation
ldadd = global_ldadd;
wxString global_res_incs;
wxString prj_res_incs;
wxString res_incs;
DoAppendResourceIncludeDirs(global_res_incs, 0L, m_CompilerSet->GetSwitches().includeDirs, true);
DoAppendResourceIncludeDirs(prj_res_incs, 0L, m_CompilerSet->GetSwitches().includeDirs);
res_incs << global_res_incs << _T(" ") << prj_res_incs << _T(" ");
DoAppendResourceIncludeDirs(res_incs, target, m_CompilerSet->GetSwitches().includeDirs);
wxString incs;
wxString global_incs;
wxString prj_incs;
DoAppendIncludeDirs(global_incs, 0L, m_CompilerSet->GetSwitches().includeDirs, true);
DoAppendIncludeDirs(prj_incs, 0L, m_CompilerSet->GetSwitches().includeDirs);
DoGetMakefileIncludes(incs, target);
if (target)
{
incs.Replace(_T("$(") + target->GetTitle() + _T("_GLOBAL_INCS)"), global_incs);
incs.Replace(_T("$(") + target->GetTitle() + _T("_PROJECT_INCS)"), prj_incs);
}
else if (!target && !pf) // probably single file compilation
incs = global_incs;
wxString libs;
wxString global_libs;
wxString prj_libs;
DoAppendLibDirs(global_libs, 0L, m_CompilerSet->GetSwitches().libDirs, true);
DoAppendLibDirs(prj_libs, 0L, m_CompilerSet->GetSwitches().libDirs);
DoGetMakefileLibDirs(libs, target);
if (target)
{
libs.Replace(_T("$(") + target->GetTitle() + _T("_GLOBAL_LIBDIRS)"), global_libs);
libs.Replace(_T("$(") + target->GetTitle() + _T("_PROJECT_LIBDIRS)"), prj_libs);
}
else if (!target && !pf) // probably single file compilation
libs = global_libs;
wxString output;
if (target)
output = UnixFilename(target->GetOutputFilename());
else
{
wxString object_unquoted(object);
if (!object_unquoted.IsEmpty() && object_unquoted.GetChar(0) == '"')
object_unquoted.Replace(_T("\""), _T(""));
wxFileName fname(object_unquoted);
fname.SetExt(EXECUTABLE_EXT);
output = fname.GetFullPath();
}
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(output);
ConvertToMakefileFriendly(output);
QuoteStringIfNeeded(output);
wxString linkobjs;
wxString compilerCmd = command;
compilerCmd.Replace(_T("$compiler"), compilerStr);
compilerCmd.Replace(_T("$linker"), m_CompilerSet->GetPrograms().LD);
compilerCmd.Replace(_T("$lib_linker"), m_CompilerSet->GetPrograms().LIB);
compilerCmd.Replace(_T("$rescomp"), m_CompilerSet->GetPrograms().WINDRES);
compilerCmd.Replace(_T("$options"), cflags);
compilerCmd.Replace(_T("$link_options"), ldflags);
compilerCmd.Replace(_T("$includes"), incs);
compilerCmd.Replace(_T("$res_includes"), res_incs);
compilerCmd.Replace(_T("$libdirs"), libs);
compilerCmd.Replace(_T("$libs"), ldadd);
compilerCmd.Replace(_T("$file"), file);
compilerCmd.Replace(_T("$dep_object"), deps);
compilerCmd.Replace(_T("$object"), object);
compilerCmd.Replace(_T("$exe_output"), output);
compilerCmd.Replace(_T("$resource_output"), object);
compilerCmd.Replace(_T("$link_resobjects"), deps);
compilerCmd.Replace(_T("$link_objects"), object);
// the following were added to support the QUICK HACK
// at directcommands.cpp:576
compilerCmd.Replace(_T("$+link_objects"), object);
compilerCmd.Replace(_T("$-link_objects"), object);
compilerCmd.Replace(_T("$-+link_objects"), object);
compilerCmd.Replace(_T("$+-link_objects"), object);
if (target && (target->GetTargetType() == ttStaticLib || target->GetTargetType() == ttDynamicLib))
{
wxFileName fname(target->GetOutputFilename());
if (!fname.GetName().StartsWith(m_CompilerSet->GetSwitches().libPrefix))
fname.SetName(m_CompilerSet->GetSwitches().libPrefix + fname.GetName());
fname.SetExt(m_CompilerSet->GetSwitches().libExtension);
wxString out = UnixFilename(fname.GetFullPath());
ConvertToMakefileFriendly(out);
QuoteStringIfNeeded(out);
if (target->GetTargetType() == ttStaticLib || target->GetCreateStaticLib())
compilerCmd.Replace(_T("$static_output"), out);
else
{
compilerCmd.Replace(_T("-Wl,--out-implib=$static_output"), _T("")); // special gcc case
compilerCmd.Replace(_T("$static_output"), _T(""));
}
if (target->GetCreateDefFile())
{
fname.SetExt(_T("def"));
out = UnixFilename(fname.GetFullPath());
ConvertToMakefileFriendly(out);
QuoteStringIfNeeded(out);
compilerCmd.Replace(_T("$def_output"), out);
}
else
{
compilerCmd.Replace(_T("-Wl,--output-def=$def_output"), _T("")); // special gcc case
compilerCmd.Replace(_T("$def_output"), _T(""));
}
}
return compilerCmd;
}
void MakefileGenerator::DoAppendCompilerOptions(wxString& cmd, ProjectBuildTarget* target, bool useGlobalOptions)
{
wxArrayString opts;
if (!m_CompilerSet)
return;
if (useGlobalOptions)
opts = m_CompilerSet->GetCompilerOptions();
else
{
if (target)
opts = target->GetCompilerOptions();
else
opts = m_Project ? m_Project->GetCompilerOptions() : m_CompilerSet->GetCompilerOptions();
}
for (unsigned int x = 0; x < opts.GetCount(); ++x)
{
if (!m_GeneratingMakefile)
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(opts[x]);
cmd << _T(" ") << opts[x];
}
}
void MakefileGenerator::DoAppendLinkerOptions(wxString& cmd, ProjectBuildTarget* target, bool useGlobalOptions)
{
CompileOptionsBase* obj;
if (!m_CompilerSet)
return;
if (useGlobalOptions)
obj = m_CompilerSet;
else
obj = target ? (CompileOptionsBase*)target : (m_Project ? (CompileOptionsBase*)m_Project : m_CompilerSet);
wxArrayString opts = obj->GetLinkerOptions();
for (unsigned int x = 0; x < opts.GetCount(); ++x)
{
if (!m_GeneratingMakefile)
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(opts[x]);
cmd << _T(" ") << opts[x];
}
}
void MakefileGenerator::DoAppendLinkerLibs(wxString& cmd, ProjectBuildTarget* target, bool useGlobalOptions)
{
if (!m_CompilerSet)
return;
CompileOptionsBase* obj;
if (useGlobalOptions)
obj = m_CompilerSet;
else
{
obj = target ? (CompileOptionsBase*)target : (m_Project ? (CompileOptionsBase*)m_Project : m_CompilerSet);
int index = target ? target->GetCompilerIndex() : (m_Project ? m_Project->GetCompilerIndex() : CompilerFactory::GetDefaultCompilerIndex());
m_CompilerSet = CompilerFactory::Compilers[index];
}
wxArrayString libs = obj->GetLinkLibs();
for (unsigned int x = 0; x < libs.GetCount(); ++x)
{
if (libs[x].IsEmpty())
continue;
// construct linker option for each lib, based on compiler's settings
wxString libPrefix = m_CompilerSet->GetSwitches().libPrefix;
wxString libExt = m_CompilerSet->GetSwitches().libExtension;
wxString lib = libs[x];
QuoteStringIfNeeded(lib);
// run replacements on libs only if no slashes in name (which means it's a relative or absolute path)
if (lib.Find('/') == -1 && lib.Find('\\') == -1)
{
// 'lib' prefix
bool hadLibPrefix = false;
if (!m_CompilerSet->GetSwitches().linkerNeedsLibPrefix &&
!libPrefix.IsEmpty() &&
lib.StartsWith(libPrefix))
{
lib.Remove(0, libPrefix.Length());
hadLibPrefix = true;
}
// extension
if (!m_CompilerSet->GetSwitches().linkerNeedsLibExtension &&
lib.Length() > libExt.Length() &&
lib.Right(libExt.Length() + 1) == _T(".") + libExt)
{
// remove the extension only if we had a lib prefix
if (hadLibPrefix)
lib.RemoveLast(libExt.Length() + 1);
}
else if (m_CompilerSet->GetSwitches().linkerNeedsLibExtension &&
!libExt.IsEmpty())
{
if (lib.Length() <= libExt.Length() ||
lib.Right(libExt.Length() + 1) != _T(".") + libExt)
{
lib << _T(".") << libExt;
}
}
lib = m_CompilerSet->GetSwitches().linkLibs + lib;
}
if (!m_GeneratingMakefile)
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(lib);
cmd << _T(" ") << lib;
}
}
void MakefileGenerator::DoAppendIncludeDirs(wxString& cmd, ProjectBuildTarget* target, const wxString& prefix, bool useGlobalOptions)
{
wxArrayString opts;
if (!m_CompilerSet)
return;
if (useGlobalOptions)
opts = m_CompilerSet->GetIncludeDirs();
else
{
if (target)
opts = target->GetIncludeDirs();
else
opts = m_Project ? m_Project->GetIncludeDirs() : m_CompilerSet->GetIncludeDirs();
}
for (unsigned int x = 0; x < opts.GetCount(); ++x)
{
if (opts[x].IsEmpty())
continue;
wxString out = UnixFilename(opts[x]);
if (!m_GeneratingMakefile)
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(out);
ConvertToMakefileFriendly(out);
QuoteStringIfNeeded(out);
cmd << _T(" ") << prefix << out;
}
}
void MakefileGenerator::DoAppendResourceIncludeDirs(wxString& cmd, ProjectBuildTarget* target, const wxString& prefix, bool useGlobalOptions)
{
wxArrayString opts;
if (!m_CompilerSet)
return;
if (useGlobalOptions)
opts = m_CompilerSet->GetResourceIncludeDirs();
else
{
if (target)
opts = target->GetResourceIncludeDirs();
else
opts = m_Project ? m_Project->GetResourceIncludeDirs() : m_CompilerSet->GetResourceIncludeDirs();
}
for (unsigned int x = 0; x < opts.GetCount(); ++x)
{
if (opts[x].IsEmpty())
continue;
wxString out = UnixFilename(opts[x]);
if (!m_GeneratingMakefile)
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(out);
ConvertToMakefileFriendly(out);
QuoteStringIfNeeded(out);
cmd << _T(" ") << prefix << out;
}
}
void MakefileGenerator::DoAppendLibDirs(wxString& cmd, ProjectBuildTarget* target, const wxString& prefix, bool useGlobalOptions)
{
wxArrayString opts;
if (!m_CompilerSet)
return;
if (useGlobalOptions)
opts = m_CompilerSet->GetLibDirs();
else
{
if (target)
opts = target->GetLibDirs();
else
opts = m_Project ? m_Project->GetLibDirs() : m_CompilerSet->GetLibDirs();
}
for (unsigned int x = 0; x < opts.GetCount(); ++x)
{
if (opts[x].IsEmpty())
continue;
wxString out = UnixFilename(opts[x]);
if (!m_GeneratingMakefile)
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(out);
ConvertToMakefileFriendly(out);
QuoteStringIfNeeded(out);
cmd << _T(" ") << prefix << out;
}
}
void MakefileGenerator::DoGetMakefileIncludes(wxString& buffer, ProjectBuildTarget* target)
{
UpdateCompiler(target);
if (!m_CompilerSet || !target)
return;
wxString prefix = m_CompilerSet->GetSwitches().includeDirs;
OptionsRelation relation = target->GetOptionRelation(ortIncludeDirs);
switch (relation)
{
case orUseParentOptionsOnly:
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_INCS)");
break;
case orUseTargetOptionsOnly:
DoAppendIncludeDirs(buffer, target, prefix);
break;
case orPrependToParentOptions:
DoAppendIncludeDirs(buffer, target, prefix);
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_INCS)");
break;
case orAppendToParentOptions:
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_INCS)");
DoAppendIncludeDirs(buffer, target, prefix);
break;
}
buffer << _T(" $(") + target->GetTitle() + _T("_GLOBAL_INCS)");
}
void MakefileGenerator::DoGetMakefileLibs(wxString& buffer, ProjectBuildTarget* target)
{
UpdateCompiler(target);
if (!m_CompilerSet || !target)
return;
OptionsRelation relation = target->GetOptionRelation(ortLinkerOptions);
switch (relation)
{
case orUseParentOptionsOnly:
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_LIBS)");
break;
case orUseTargetOptionsOnly:
DoAppendLinkerLibs(buffer, target);
break;
case orPrependToParentOptions:
DoAppendLinkerLibs(buffer, target);
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_LIBS)");
break;
case orAppendToParentOptions:
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_LIBS)");
DoAppendLinkerLibs(buffer, target);
break;
}
buffer << _T(" $(") + target->GetTitle() + _T("_GLOBAL_LIBS)");
}
void MakefileGenerator::DoGetMakefileLibDirs(wxString& buffer, ProjectBuildTarget* target)
{
UpdateCompiler(target);
if (!m_CompilerSet || !target)
return;
wxString prefix = m_CompilerSet->GetSwitches().libDirs;
OptionsRelation relation = target->GetOptionRelation(ortLibDirs);
switch (relation)
{
case orUseParentOptionsOnly:
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_LIBDIRS)");
break;
case orUseTargetOptionsOnly:
DoAppendLibDirs(buffer, target, prefix);
break;
case orPrependToParentOptions:
DoAppendLibDirs(buffer, target, prefix);
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_LIBDIRS)");
break;
case orAppendToParentOptions:
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_LIBDIRS)");
DoAppendLibDirs(buffer, target, prefix);
break;
}
buffer << _T(" $(") + target->GetTitle() + _T("_GLOBAL_LIBDIRS)");
}
void MakefileGenerator::DoGetMakefileCFlags(wxString& buffer, ProjectBuildTarget* target)
{
UpdateCompiler();
if (!m_CompilerSet || !target)
return;
OptionsRelation relation = target->GetOptionRelation(ortCompilerOptions);
switch (relation)
{
case orUseParentOptionsOnly:
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_CFLAGS)");
break;
case orUseTargetOptionsOnly:
DoAppendCompilerOptions(buffer, target);
break;
case orPrependToParentOptions:
DoAppendCompilerOptions(buffer, target);
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_CFLAGS)");
break;
case orAppendToParentOptions:
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_CFLAGS)");
DoAppendCompilerOptions(buffer, target);
break;
}
buffer << _T(" $(") + target->GetTitle() + _T("_GLOBAL_CFLAGS)");
}
void MakefileGenerator::DoGetMakefileLDFlags(wxString& buffer, ProjectBuildTarget* target)
{
UpdateCompiler(target);
if (!m_CompilerSet || !target)
return;
OptionsRelation relation = target->GetOptionRelation(ortLinkerOptions);
switch (relation)
{
case orUseParentOptionsOnly:
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_LDFLAGS)");
break;
case orUseTargetOptionsOnly:
DoAppendLinkerOptions(buffer, target);
break;
case orPrependToParentOptions:
DoAppendLinkerOptions(buffer, target);
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_LDFLAGS)");
break;
case orAppendToParentOptions:
buffer << _T(" $(") + target->GetTitle() + _T("_PROJECT_LDFLAGS)");
DoAppendLinkerOptions(buffer, target);
break;
}
buffer << _T(" $(") + target->GetTitle() + _T("_GLOBAL_LDFLAGS)");
}
void MakefileGenerator::DoAddVarsSet(wxString& buffer, CustomVars& vars)
{
const VarsArray& v = vars.GetVars();
for (unsigned int i = 0; i < v.GetCount(); ++i)
{
wxString out = v[i].value;
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(out);
ConvertToMakefileFriendly(out);
QuoteStringIfNeeded(out);
buffer << v[i].name << _T("=") << out << _T('\n');
}
}
void MakefileGenerator::DoAddMakefileVars(wxString& buffer)
{
buffer << _T("### Variables used in this Makefile") << _T('\n');
// compiler global vars
DoAddVarsSet(buffer, CompilerFactory::Compilers[m_Project->GetCompilerIndex()]->GetCustomVars());
// project vars
DoAddVarsSet(buffer, m_Project->GetCustomVars());
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!IsTargetValid(target))
continue;
Compiler* compilerSet = CompilerFactory::Compilers[target->GetCompilerIndex()];
// target vars
DoAddVarsSet(buffer, compilerSet->GetCustomVars());
// compiler vars
// defined last so even if the user sets custom vars
// by these names, ours will have precedence...
buffer << target->GetTitle() << _T("_CC=") << compilerSet->GetPrograms().C << _T('\n');
buffer << target->GetTitle() << _T("_CPP=") << compilerSet->GetPrograms().CPP << _T('\n');
buffer << target->GetTitle() << _T("_LD=") << compilerSet->GetPrograms().LD << _T('\n');
buffer << target->GetTitle() << _T("_LIB=") << compilerSet->GetPrograms().LIB << _T('\n');
buffer << target->GetTitle() << _T("_RESCOMP=") << compilerSet->GetPrograms().WINDRES << _T('\n');
}
buffer << _T('\n');
}
#ifdef __WXMSW__
void MakefileGenerator::DoAddMakefileResources(wxString& buffer)
{
buffer << _T("### Resources used in this Makefile") << _T('\n');
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
break;
// create target's options only if it has at least one linkable file
if (!IsTargetValid(target))
continue;
buffer << target->GetTitle() << _T("_RESOURCE=");
if (target->GetTargetType() == ttConsoleOnly)
{
buffer << _T('\n');
break;
}
wxFileName resFile;
resFile.SetName(target->GetTitle() + _T("_private"));
resFile.SetExt(RESOURCEBIN_EXT);
resFile.MakeRelativeTo(m_Project->GetBasePath());
// now create the resource file...
bool hasResources = false;
wxString resBuf;
resBuf << _T("#include <windows.h>") << _T('\n');
int filesCount = (int)m_Files.GetCount();
for (int i = 0; i < filesCount; ++i)
{
wxFileName file;
ProjectFile* pf = m_Files[i];
// if the file is allowed to compile *and* belongs in this target
if (pf->link && pf->buildTargets.Index(target->GetTitle()) >= 0)
{
file.Assign(pf->relativeFilename);
if (file.GetExt().Lower().Matches(_T("rc")))
{
resBuf << _T("#include \"") << file.GetFullPath() << _T("\"") << _T('\n');
hasResources = true;
}
}
}
if (hasResources)
{
wxString out = UnixFilename(resFile.GetFullPath());
ConvertToMakefileFriendly(out);
QuoteStringIfNeeded(out);
buffer << out << _T('\n');
// write private resource file to disk
resFile.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, m_Project->GetBasePath());
resFile.SetExt(RESOURCE_EXT);
wxFile file(resFile.GetFullPath(), wxFile::write);
cbWrite(file,resBuf);
}
else
buffer << _T('\n');
}
buffer << _T('\n');
}
#endif // __WXMSW__
void MakefileGenerator::DoAddMakefileCreateDirs(wxString& buffer, ProjectBuildTarget* target, bool obj, bool dep, bool bin)
{
if (!target)
return;
// create target's options only if it has at least one linkable file
if (!IsTargetValid(target))
return;
wxArrayString addedDirs; // avoid creating multiple commands for the same dir
int filesCount = (int)m_Files.GetCount();
if (obj)
{
// object output dirs
addedDirs.Clear();
for (int i = 0; i < filesCount; ++i)
{
ProjectFile* pf = m_Files[i];
// if the file belongs in this target
if (pf->buildTargets.Index(target->GetTitle()) >= 0)
{
wxString sep = wxFileName::GetPathSeparator();
wxString o_out = target->GetObjectOutput();
wxString object_file = (!o_out.IsEmpty() ? o_out : _T(".")) +
sep +
pf->GetObjName();
wxFileName o_file(object_file);
wxFileName o_dir(o_file.GetPath(wxPATH_GET_SEPARATOR));
RecursiveCreateDir(buffer, o_dir.GetDirs(), addedDirs);
}
}
}
if (dep)
{
// deps output dirs
addedDirs.Clear();
for (int i = 0; i < filesCount; ++i)
{
ProjectFile* pf = m_Files[i];
// if the file belongs in this target
if (pf->buildTargets.Index(target->GetTitle()) >= 0)
{
wxString sep = wxFileName::GetPathSeparator();
wxString o_out = target->GetDepsOutput();
wxString object_file = (!o_out.IsEmpty() ? o_out : _T(".")) +
sep +
pf->GetObjName();
wxFileName o_file(object_file);
wxFileName o_dir(o_file.GetPath(wxPATH_GET_SEPARATOR));
RecursiveCreateDir(buffer, o_dir.GetDirs(), addedDirs);
}
}
}
if (bin)
{
// add output dir also
addedDirs.Clear();
wxFileName fname(target->GetOutputFilename());
if (fname.IsAbsolute())
fname.MakeRelativeTo(m_Project->GetBasePath());
wxString out = UnixFilename(fname.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR));
if (!out.IsEmpty())
{
ConvertToMakefileFriendly(out);
QuoteStringIfNeeded(out);
wxFileName o_file(out);
wxFileName o_dir(o_file.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR));
RecursiveCreateDir(buffer, o_dir.GetDirs(), addedDirs);
}
}
}
void MakefileGenerator::RecursiveCreateDir(wxString& buffer, const wxArrayString& subdirs, wxArrayString& guardList)
{
wxString currdir;
for (size_t i = 0; i < subdirs.GetCount(); ++i)
{
wxString sub = subdirs[i];
#ifdef __WXMSW__
if (m_GeneratingMakefile)
{
// Can't do it differently here...
// We *must* replace the env vars if we 're running under windows
// because the windows command shell is *really* dumb...
// If we use an env. var in output and this env. var contains
// path separators, it breaks under windows...
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(sub);
}
#endif
currdir << sub;
if (guardList.Index(currdir) != wxNOT_FOUND)
{
currdir << wxFileName::GetPathSeparator();
continue;
}
guardList.Add(currdir);
#ifdef __WXMSW__
buffer << _T("\t-@if not exist \"") << currdir << wxFileName::GetPathSeparator() << _T(".\" mkdir \"") << currdir << _T("\"\n");
#else
wxString out = currdir;
ConvertToMakefileFriendly(out);
QuoteStringIfNeeded(out);
buffer << _T("\t-@if ! test -d ") << out << _T("; then mkdir ") << out << _T("; fi\n");
#endif
currdir << wxFileName::GetPathSeparator();
}
}
void MakefileGenerator::DoAddMakefileObjs(wxString& buffer)
{
buffer << _T("### Objects used in this Makefile") << _T('\n');
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
break;
// create target's options only if it has at least one linkable file
if (!IsTargetValid(target))
continue;
UpdateCompiler(target);
wxString deps;
wxString tmp;
wxString tmpLink;
int filesCount = (int)m_Files.GetCount();
for (int i = 0; i < filesCount; ++i)
{
wxFileName file;
ProjectFile* pf = m_Files[i];
// if the file belongs in this target
if (pf->buildTargets.Index(target->GetTitle()) >= 0)
{
if (FileTypeOf(pf->relativeFilename) == ftResource)
continue; // resource file are treated differently
wxString fname = UnixFilename(pf->GetObjName());
// ConvertToMakefileFriendly(fname);
wxFileName deps_tmp = fname;
deps_tmp.SetExt(_T("d"));
wxString depsS;
depsS << target->GetDepsOutput() << _T("/") << deps_tmp.GetFullPath();
wxFileName objs_tmp = fname;
wxString objsS;
objsS << target->GetObjectOutput() << _T("/") << fname;
objsS = UnixFilename(objsS);
ConvertToMakefileFriendly(objsS);
QuoteStringIfNeeded(objsS);
depsS = UnixFilename(depsS);
ConvertToMakefileFriendly(depsS);
QuoteStringIfNeeded(depsS);
if (pf->compile)
{
deps << depsS << _T(" ");
tmp << objsS << _T(" "); // if the file is allowed to compile
}
if (pf->link)
tmpLink << objsS << _T(" "); // if the file is allowed to link
}
}
buffer << target->GetTitle() << _T("_OBJS=") << tmp << _T('\n');
buffer << target->GetTitle() << _T("_LINKOBJS=");
if (tmp.Matches(tmpLink))
buffer << _T("$(") << target->GetTitle() << _T("_OBJS)");
else
buffer << tmpLink; // only write *_LINKOBJS if different from *_OBJS
// if (target->GetTargetType() != ttConsoleOnly)
// buffer << _T(" $(") << target->GetTitle() << _T("_RESOURCE)";
buffer << _T('\n');
if (m_CompilerSet->GetSwitches().needDependencies)
{
buffer << target->GetTitle() << _T("_DEPS=") << deps << _T('\n');
// buffer << target->GetTitle() << _T("_DEPS=$(") << target->GetTitle() << _T("_OBJS:.";
// buffer << m_CompilerSet->GetSwitches().objectExtension;
// buffer << _T("=.d)") << _T('\n');
}
}
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileOptions(wxString& buffer)
{
buffer << _T("### Compiler/linker options") << _T('\n');
for (int i = 0; i < m_Project->GetBuildTargetsCount(); ++i)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(i);
UpdateCompiler(target);
if (!m_CompilerSet)
continue;
buffer << target->GetTitle() + _T("_GLOBAL_CFLAGS=");
DoAppendCompilerOptions(buffer, 0L, true);
buffer << _T('\n');
buffer << target->GetTitle() + _T("_PROJECT_CFLAGS=");
DoAppendCompilerOptions(buffer, 0L);
buffer << _T('\n');
buffer << target->GetTitle() + _T("_GLOBAL_LDFLAGS=");
DoAppendLinkerOptions(buffer, 0L, true);
buffer << _T('\n');
buffer << target->GetTitle() + _T("_PROJECT_LDFLAGS=");
DoAppendLinkerOptions(buffer, 0L);
buffer << _T('\n');
buffer << target->GetTitle() + _T("_GLOBAL_INCS=");
DoAppendIncludeDirs(buffer, 0L, m_CompilerSet->GetSwitches().includeDirs, true);
buffer << _T('\n');
buffer << target->GetTitle() + _T("_PROJECT_INCS=");
DoAppendIncludeDirs(buffer, 0L, m_CompilerSet->GetSwitches().includeDirs);
buffer << _T('\n');
buffer << target->GetTitle() + _T("_GLOBAL_LIBDIRS=");
DoAppendLibDirs(buffer, 0L, m_CompilerSet->GetSwitches().libDirs, true);
buffer << _T('\n');
buffer << target->GetTitle() + _T("_PROJECT_LIBDIRS=");
DoAppendLibDirs(buffer, 0L, m_CompilerSet->GetSwitches().libDirs);
buffer << _T('\n');
buffer << target->GetTitle() + _T("_GLOBAL_LIBS=");
DoAppendLinkerLibs(buffer, 0L, true);
buffer << _T('\n');
buffer << target->GetTitle() + _T("_PROJECT_LIBS=");
DoAppendLinkerLibs(buffer, 0L);
buffer << _T('\n');
}
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileIncludes(wxString& buffer)
{
buffer << _T("### Targets include directories") << _T('\n');
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
break;
// create target's options only if it has at least one linkable file
if (!IsTargetValid(target))
continue;
wxString tmp;
DoGetMakefileIncludes(tmp, target);
buffer << target->GetTitle() << _T("_INCS=") << tmp << _T('\n');
}
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileLibs(wxString& buffer)
{
buffer << _T("### Targets libraries") << _T('\n');
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
break;
// create target's options only if it has at least one linkable file
if (!IsTargetValid(target))
continue;
wxString tmp;
DoGetMakefileLibs(tmp, target);
buffer << target->GetTitle() << _T("_LIBS=") << tmp << _T('\n');
}
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileLibDirs(wxString& buffer)
{
buffer << _T("### Targets library directories") << _T('\n');
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
break;
// create target's options only if it has at least one linkable file
if (!IsTargetValid(target))
continue;
wxString tmp;
DoGetMakefileLibDirs(tmp, target);
buffer << target->GetTitle() << _T("_LIBDIRS=") << tmp << _T('\n');
}
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileCFlags(wxString& buffer)
{
buffer << _T("### Targets compiler flags") << _T('\n');
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
break;
// create target's options only if it has at least one linkable file
if (!IsTargetValid(target))
continue;
wxString tmp;
DoGetMakefileCFlags(tmp, target);
buffer << target->GetTitle() << _T("_CFLAGS=") << tmp << _T('\n');
}
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileLDFlags(wxString& buffer)
{
buffer << _T("### Targets linker flags") << _T('\n');
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
break;
// create target's options only if it has at least one linkable file
if (!IsTargetValid(target))
continue;
wxString tmp;
DoGetMakefileLDFlags(tmp, target);
buffer << target->GetTitle() << _T("_LDFLAGS=") << tmp;
buffer << _T('\n');
}
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileTargets(wxString& buffer)
{
buffer << _T("### The targets of this project") << _T('\n');
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
break;
// create target's options only if it has at least one linkable file
if (!IsTargetValid(target))
continue;
UpdateCompiler(target);
// the filename is already adapted based on the project type
wxString out = UnixFilename(target->GetOutputFilename());
if (!m_GeneratingMakefile)
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(out);
ConvertToMakefileFriendly(out);
// QuoteStringIfNeeded(out);
buffer << target->GetTitle() << _T("_BIN=") << out << _T('\n');
if (target->GetTargetType() == ttDynamicLib)
{
wxFileName fname(target->GetOutputFilename());
if (!fname.GetName().StartsWith(m_CompilerSet->GetSwitches().libPrefix))
fname.SetName(m_CompilerSet->GetSwitches().libPrefix + fname.GetName());
fname.SetExt(m_CompilerSet->GetSwitches().libExtension);
out = UnixFilename(fname.GetFullPath());
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(out);
ConvertToMakefileFriendly(out);
QuoteStringIfNeeded(out);
buffer << target->GetTitle() << _T("_STATIC_LIB=") << out << _T('\n');
fname.SetExt(_T("def"));
out = UnixFilename(fname.GetFullPath());
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(out);
ConvertToMakefileFriendly(out);
QuoteStringIfNeeded(out);
buffer << target->GetTitle() << _T("_LIB_DEF=") << out << _T('\n');
}
}
buffer << _T('\n');
}
void MakefileGenerator::DoAddPhonyTargets(wxString& buffer)
{
wxString tmp;
tmp << _T("all all-before all-custom all-after clean clean-custom distclean distclean-custom ");
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!IsTargetValid(target))
continue;
tmp << _T("depend_") << target->GetTitle() << _T(" ")
<< target->GetTitle() << _T("-before ")
<< target->GetTitle() << _T("-after ");
}
buffer << _T(".PHONY: ") << tmp << _T('\n');
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileTarget_All(wxString& buffer)
{
wxString tmp;
wxString deps;
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
continue;
UpdateCompiler(target);
if (target->GetIncludeInTargetAll())
{
// create target's options only if it has at least one linkable file
// or custom commands...
if (IsTargetValid(target))
{
tmp << target->GetTitle() << _T(" ");
// to include dependencies, the target must have linkable files...
// if (m_LinkableTargets.Index(target) != -1 && m_CompilerSet->GetSwitches().needDependencies)
// deps << _T("-include $(") << target->GetTitle() << _T("_DEPS)") << _T('\n');
}
}
}
if (!tmp.IsEmpty()) // include target "all" first, so it is the default target
buffer << _T("all: all-before ") << tmp << _T("all-after") << _T('\n');
if (!deps.IsEmpty()) // include dependencies too
buffer << deps;
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileCommands(const wxString& desc, const wxString& prefix, const wxArrayString& commands, wxString& buffer)
{
if (!m_CompilerSet)
return;
if (commands.GetCount())
{
// run any user-defined commands *before* build
if (!prefix.IsEmpty())
buffer << prefix << _T(": ") << _T('\n');
if (m_CompilerSet->GetSwitches().logging == clogSimple)
buffer << _T('\t') << _T("@echo ") << desc << _T('\n');
for (unsigned int i = 0; i < commands.GetCount(); ++i)
{
wxString tmp = commands[i];
Manager::Get()->GetMacrosManager()->ReplaceMacros(tmp);
buffer << _T('\t') << m_Quiet << tmp << _T('\n');
}
buffer << _T('\n');
}
}
void MakefileGenerator::DoAddMakefileTargets_BeforeAfter(wxString& buffer)
{
DoAddMakefileCommands(_T("Running project pre-build step"), _T("all-before"), m_Project->GetCommandsBeforeBuild(), buffer);
DoAddMakefileCommands(_T("Running project post-build step"), _T("all-after"), m_Project->GetCommandsAfterBuild(), buffer);
wxString tmp;
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target || !IsTargetValid(target))
continue;
tmp.Clear();
tmp << target->GetTitle() << _T("-before");
DoAddMakefileCommands(_("Running pre-build step"), tmp, target->GetCommandsBeforeBuild(), buffer);
tmp.Clear();
tmp << target->GetTitle() << _T("-after");
DoAddMakefileCommands(_("Running post-build step"), tmp, target->GetCommandsAfterBuild(), buffer);
}
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileTarget_Clean(wxString& buffer)
{
wxString tmp;
wxString tmp1;
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
break;
// create target's options only if it has at least one linkable file
if (!IsTargetValid(target))
continue;
UpdateCompiler(target);
buffer << _T("clean_") << target->GetTitle() << _T(":") << _T('\n');
if (m_CompilerSet->GetSwitches().logging == clogSimple)
buffer << _T('\t') << _T("@echo Cleaning target \"") << target->GetTitle() << _T("\"...") << _T('\n');
buffer << _T('\t') << m_Quiet << _T("$(RM) $(") << target->GetTitle() << _T("_BIN) ");
buffer << _T("$(") << target->GetTitle() << _T("_OBJS) ");
buffer << _T("$(") << target->GetTitle() << _T("_RESOURCE) ");
if (target->GetTargetType() == ttDynamicLib)
{
buffer << _T("$(") << target->GetTitle() << _T("_STATIC_LIB) ");
buffer << _T("$(") << target->GetTitle() << _T("_LIB_DEF) ");
}
buffer << _T('\n') << _T('\n');
tmp << _T("clean_") << target->GetTitle() << _T(" ");
buffer << _T("distclean_") << target->GetTitle() << _T(":") << _T('\n');
if (m_CompilerSet->GetSwitches().logging == clogSimple)
buffer << _T('\t') << _T("@echo Dist-cleaning target \"") << target->GetTitle() << _T("\"...") << _T('\n');
buffer << _T('\t') << m_Quiet << _T("$(RM) $(") << target->GetTitle() << _T("_BIN) ");
buffer << _T("$(") << target->GetTitle() << _T("_OBJS) ");
buffer << _T("$(") << target->GetTitle() << _T("_DEPS) ");
buffer << _T("$(") << target->GetTitle() << _T("_RESOURCE) ");
if (target->GetTargetType() == ttDynamicLib)
{
buffer << _T("$(") << target->GetTitle() << _T("_STATIC_LIB) ");
buffer << _T("$(") << target->GetTitle() << _T("_LIB_DEF) ");
}
buffer << _T('\n') << _T('\n');
tmp1 << _T("distclean_") << target->GetTitle() << _T(" ");
}
buffer << _T("clean: ") << tmp << _T('\n');
buffer << _T('\n');
buffer << _T("distclean: ") << tmp1 << _T('\n');
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileTarget_Dist(wxString& buffer)
{
wxString tmp = _T("${PROJECT_FILENAME} ${MAKEFILE} ${ALL_PROJECT_FILES}");
Manager::Get()->GetMacrosManager()->ReplaceMacros(tmp);
wxFileName fname(m_Project->GetFilename());
wxString projname = UnixFilename(fname.GetFullName());
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(projname);
ConvertToMakefileFriendly(projname);
QuoteStringIfNeeded(projname);
buffer << _T("dist:") << _T('\n');
buffer << _T('\t') << _T("@zip ") << projname << _T(".zip ") << tmp << _T('\n');
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileTarget_Depend(wxString& buffer)
{
wxString tmp;
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
continue;
// create target's options only if it has at least one linkable file
if (!IsTargetValid(target))
continue;
UpdateCompiler(target);
if (!m_CompilerSet->GetSwitches().needDependencies)
continue;
buffer << _T("depend_") << target->GetTitle() << _T("_DIRS:") << _T('\n');
DoAddMakefileCreateDirs(buffer, target, false, true, false);
buffer << _T('\n');
buffer << _T("depend_") << target->GetTitle() << _T(": depend_") << target->GetTitle() << _T("_DIRS $(") << target->GetTitle() << _T("_DEPS)") << _T('\n');
buffer << _T('\n');
tmp << _T(" depend_") << target->GetTitle();
}
buffer << _T("depend:") << tmp << _T('\n');
buffer << _T('\n');
}
void MakefileGenerator::DoAddMakefileTarget_Link(wxString& buffer)
{
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
UpdateCompiler(target);
if (!IsTargetValid(target))
continue;
buffer << target->GetTitle() << _T("_DIRS:") << _T('\n');
DoAddMakefileCreateDirs(buffer, target, true, false, true);
buffer << _T('\n');
buffer << target->GetTitle() << _T(": depend_") << target->GetTitle() << _T(" ") << target->GetTitle() << _T("_DIRS ") << target->GetTitle() << _T("-before ");
if (IsTargetValid(target))
{
buffer << _T("$(") << target->GetTitle() << _T("_BIN) ");
// add all custom-built files that do *not* link
int filesCount = (int)m_Files.GetCount();
for (int i = 0; i < filesCount; ++i)
{
ProjectFile* pf = m_Files[i];
if (pf->useCustomBuildCommand && !pf->link)
buffer << pf->relativeFilename << _T(" ");
}
}
buffer << target->GetTitle() << _T("-after") << _T('\n');
buffer << _T('\n');
// create target's options only if it has at least one linkable file
if (!IsTargetValid(target))
continue;
buffer << _T("$(") << target->GetTitle() << _T("_BIN): ") << _T("$(") << target->GetTitle() << _T("_LINKOBJS) $(") << target->GetTitle() << _T("_RESOURCE)");
// add external deps
wxArrayString array = GetArrayFromString(target->GetExternalDeps());
for (unsigned int i = 0; i < array.GetCount(); ++i)
{
buffer << _T(' ') << UnixFilename(array[i]);
}
buffer << _T('\n');
// change link stage command based on target type
switch (target->GetTargetType())
{
case ttConsoleOnly:
case ttExecutable:
{
CommandType ct = target->GetTargetType() == ttConsoleOnly ? ctLinkConsoleExeCmd : ctLinkExeCmd;
if (m_CompilerSet->GetSwitches().logging == clogSimple)
buffer << _T('\t') << _T("@echo Linking executable \"") << target->GetOutputFilename() << _T("\"...") << _T('\n');
wxString compilerCmd = ReplaceCompilerMacros(ct, _T(""), target, _T(""), _T(""), _T(""));
buffer << _T('\t') << m_Quiet << compilerCmd<< _T('\n');
break;
}
case ttStaticLib:
{
if (m_CompilerSet->GetSwitches().logging == clogSimple)
buffer << _T('\t') << _T("@echo Linking static library \"") << target->GetOutputFilename() << _T("\"...") << _T('\n');
wxString compilerCmd = ReplaceCompilerMacros(ctLinkStaticCmd, _T(""), target, _T(""), _T(""), _T(""));
buffer << _T('\t') << m_Quiet << compilerCmd<< _T('\n');
break;
}
case ttDynamicLib:
{
if (m_CompilerSet->GetSwitches().logging == clogSimple)
buffer << _T('\t') << _T("@echo Linking shared library \"") << target->GetOutputFilename() << _T("\"...") << _T('\n');
wxString compilerCmd = ReplaceCompilerMacros(ctLinkDynamicCmd, _T(""), target, _T(""), _T(""), _T(""));
buffer << _T('\t') << m_Quiet << compilerCmd<< _T('\n');
break;
}
default: break;
}
buffer << _T('\n');
}
buffer << _T('\n');
}
void MakefileGenerator::ConvertToMakefileFriendly(wxString& str, bool force)
{
if (!force && !m_GeneratingMakefile)
return;
if (str.IsEmpty())
return;
str.Replace(_T("\\"), _T("/"));
for (unsigned int i = 0; i < str.Length(); ++i)
{
if (str[i] == _T(' ') && (i > 0 && str[i - 1] != _T('\\')))
str.insert(i, _T('\\'));
}
// str.Replace("\\\\", "/");
}
void MakefileGenerator::QuoteStringIfNeeded(wxString& str, bool force)
{
if (!force && m_GeneratingMakefile)
return;
if (m_CompilerSet->GetSwitches().forceCompilerUseQuotes ||
m_CompilerSet->GetSwitches().forceLinkerUseQuotes ||
(str.Find(' ') != -1 && str.GetChar(0) != '"'))
{
str = _T('"') + str + _T('"');
}
}
wxString MakefileGenerator::GetObjectFile(ProjectFile* pf, ProjectBuildTarget* target)
{
wxFileName o_filename_tmp = UnixFilename(pf->GetObjName());
wxFileName o_filename = target->GetObjectOutput() + wxFILE_SEP_PATH + o_filename_tmp.GetFullPath();
// vars to make easier reading the following code
wxString o_file = UnixFilename(o_filename.GetFullPath());
ConvertToMakefileFriendly(o_file);
QuoteStringIfNeeded(o_file);
return o_file;
}
wxString MakefileGenerator::GetDependencyFile(ProjectFile* pf, ProjectBuildTarget* target)
{
wxFileName d_filename_tmp = UnixFilename(pf->GetObjName());
wxFileName d_filename = target->GetDepsOutput() + wxFILE_SEP_PATH + d_filename_tmp.GetFullPath();
d_filename.SetExt(_T("d"));
wxString d_file;
UpdateCompiler(target);
if (!m_CompilerSet)
return d_file;
if (m_CompilerSet->GetSwitches().needDependencies)
{
d_file = UnixFilename(d_filename.GetFullPath());
ConvertToMakefileFriendly(d_file);
QuoteStringIfNeeded(d_file);
}
return d_file;
}
void MakefileGenerator::DoAddMakefileTarget_Objs(wxString& buffer)
{
m_ObjectFiles.Clear();
wxString tmp;
wxArrayString depfiles; // one occurrence per dep (case where the same file is used in more than one target)
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
break;
UpdateCompiler(target);
if (!IsTargetValid(target))
continue;
#ifdef __WXMSW__
wxString resources;
#endif // __WXMSW__
int filesCount = (int)m_Files.GetCount();
for (int i = 0; i < filesCount; ++i)
{
ProjectFile* pf = m_Files[i];
if (pf->compile &&
!pf->compilerVar.IsEmpty() &&
pf->buildTargets.Index(target->GetTitle()) >= 0)
{
// vars to make easier reading the following code
wxString o_file = GetObjectFile(pf, target);
wxString d_file = GetDependencyFile(pf, target);
wxString c_file = UnixFilename(pf->relativeFilename);
ConvertToMakefileFriendly(c_file);
QuoteStringIfNeeded(c_file);
wxString targetName = target->GetTitle();
bool isResource = FileTypeOf(pf->relativeFilename) == ftResource;
if (!isResource)
{
if (m_CompilerSet->GetSwitches().needDependencies &&
depfiles.Index(d_file) == wxNOT_FOUND)
{
depfiles.Add(d_file);
if (pf->autoDeps)
{
// depend rule
buffer << d_file << _T(": ") << c_file << _T('\n');
if (m_CompilerSet->GetSwitches().logging == clogSimple)
buffer << _T('\t') << _T("@echo Calculating dependencies for \"") << pf->relativeFilename << _T("\"...") << _T('\n');
// gather all object files generated from this source file (multiple targets case)
wxString tmpdep;
for (unsigned int i = 0; i < pf->buildTargets.GetCount(); ++i)
{
ProjectBuildTarget* tmptarget = m_Project->GetBuildTarget(pf->buildTargets[i]);
if (tmptarget)
tmpdep << GetObjectFile(pf, tmptarget) << _T(',');
}
if (tmpdep.Last() == _T(','))
tmpdep.RemoveLast();
wxString compilerCmd = ReplaceCompilerMacros(ctGenDependenciesCmd, pf->compilerVar, target, c_file, tmpdep, d_file);
if (!compilerCmd.IsEmpty())
buffer << _T('\t') << m_Quiet << compilerCmd << _T('\n');
buffer << _T('\n');
}
else if (!pf->customDeps.IsEmpty())
{
// custom depend rule
wxString customDeps = pf->customDeps;
ReplaceMacros(target, pf, customDeps);
buffer << d_file << _T(": ") << c_file << _T('\n');
if (m_CompilerSet->GetSwitches().logging == clogSimple)
buffer << _T('\t') << _T("@echo Generating dependencies for \"") << pf->relativeFilename << _T("\"... (custom dependencies)") << _T('\n');
buffer << _T('\t') << m_Quiet << customDeps << _T('\n');
buffer << _T('\n');
}
}
else
d_file = UnixFilename(pf->relativeFilename); // for compilers that don't need deps, use .cpp file
if (pf->useCustomBuildCommand)
{
// custom build command
wxString customBuild = pf->buildCommand;
ReplaceMacros(target, pf, customBuild);
wxString obj_file = target->GetObjectOutput() + wxFILE_SEP_PATH + pf->GetObjName();
ConvertToMakefileFriendly(obj_file);
buffer << obj_file << _T(": ") << d_file << _T('\n');
if (m_CompilerSet->GetSwitches().logging == clogSimple)
buffer << _T('\t') << _T("@echo Compiling \"") << pf->relativeFilename << _T("\" (custom command)...") << _T('\n');
buffer << _T('\t') << m_Quiet << customBuild << _T('\n');
buffer << _T('\n');
}
else
{
// compile rule
buffer << o_file << _T(": ") << d_file << _T('\n');
if (m_CompilerSet->GetSwitches().logging == clogSimple)
buffer << _T('\t') << _T("@echo Compiling \"") << pf->relativeFilename << _T("\"...") << _T('\n');
// AddCreateSubdir(buffer, target->GetBasePath(), pf->GetObjName(), target->GetObjectOutput());
wxString compilerCmd = ReplaceCompilerMacros(ctCompileObjectCmd, pf->compilerVar, target, c_file, o_file, d_file);
if (!compilerCmd.IsEmpty())
buffer << _T('\t') << m_Quiet << compilerCmd << _T('\n');
buffer << _T('\n');
}
}
else
{
#ifdef __WXMSW__
if (pf->compile && FileTypeOf(pf->relativeFilename) == ftResource)
{
wxString out = pf->relativeFilename;
ConvertToMakefileFriendly(out);
resources << out << _T(" ");
}
#endif // __WXMSW__
}
}
}
#ifdef __WXMSW__
if (!resources.IsEmpty())
{
wxFileName resFile;
resFile.SetName(target->GetTitle() + _T("_private"));
resFile.SetExt(RESOURCE_EXT);
resFile.MakeRelativeTo(m_Project->GetBasePath());
buffer << _T("$(") << target->GetTitle() << _T("_RESOURCE): ");
if (m_CompilerSet->GetSwitches().needDependencies)
buffer << resources;
buffer << _T('\n');
if (m_CompilerSet->GetSwitches().logging == clogSimple)
buffer << _T('\t') << _T("@echo Compiling resources...") << _T('\n');
wxString compilerCmd = ReplaceCompilerMacros(ctCompileResourceCmd, _T(""), target, UnixFilename(resFile.GetFullPath()), _T(""), _T(""));
if (!compilerCmd.IsEmpty())
buffer << _T('\t') << m_Quiet << compilerCmd << _T('\n');
/*buffer << _T('\t') << m_Quiet << _T("$(RESCOMP) -i ") << UnixFilename(resFile.GetFullPath()) << _T(" -J rc ");
buffer << _T("-o $(") << target->GetTitle() << _T("_RESOURCE) -O coff ");
DoAppendIncludeDirs(buffer, 0L, _T("--include-dir="), true);
DoAppendIncludeDirs(buffer, 0L, _T("--include-dir=");
DoAppendIncludeDirs(buffer, target, _T("--include-dir=");*/
buffer << _T('\n');
}
buffer << _T('\n');
#endif // __WXMSW__
}
buffer << _T('\n');
}
int SortProjectFilesByWeight(ProjectFile** one, ProjectFile** two)
{
return (*one)->weight - (*two)->weight;
}
void MakefileGenerator::DoPrepareFiles()
{
m_Files.Clear();
for (int i = 0; i < m_Project->GetFilesCount(); ++i)
{
ProjectFile* pf = m_Project->GetFile(i);
m_Files.Add(pf);
}
m_Files.Sort(SortProjectFilesByWeight);
}
void MakefileGenerator::DoPrepareValidTargets()
{
m_LinkableTargets.Clear();
int targetsCount = m_Project->GetBuildTargetsCount();
for (int x = 0; x < targetsCount; ++x)
{
ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
if (!target)
continue;
// create link target only if it has at least one linkable file
bool hasFiles = false;
for (unsigned int i = 0; i < m_Files.GetCount(); ++i)
{
ProjectFile* pf = m_Files[i];
if (pf->link && pf->buildTargets.Index(target->GetTitle()) >= 0)
{
hasFiles = true;
break;
}
}
if (hasFiles)
m_LinkableTargets.Add(target);
}
}
bool MakefileGenerator::IsTargetValid(ProjectBuildTarget* target)
{
UpdateCompiler(target);
if (!m_CompilerSet || !target)
return false;
bool hasBin = target->GetTargetType() != ttCommandsOnly; // is not "commands-only" target
bool hasCmds = !target->GetCommandsAfterBuild().IsEmpty() ||
!target->GetCommandsBeforeBuild().IsEmpty();
return hasBin && (hasCmds || m_LinkableTargets.Index(target) != -1);
}
void MakefileGenerator::ReplaceMacros(ProjectBuildTarget* bt, ProjectFile* pf, wxString& text)
{
wxString o_dir = bt ? bt->GetObjectOutput() + wxFILE_SEP_PATH : _T("");
wxString d_dir = bt ? bt->GetDepsOutput() + wxFILE_SEP_PATH : _T("");
wxFileName d_filename = d_dir + pf->GetObjName();
d_filename.SetExt(_T("d"));
wxString d_file = d_filename.GetFullPath();
ConvertToMakefileFriendly(o_dir);
ConvertToMakefileFriendly(d_dir);
ConvertToMakefileFriendly(d_file);
QuoteStringIfNeeded(o_dir);
QuoteStringIfNeeded(d_dir);
QuoteStringIfNeeded(d_file);
wxFileName fname(pf->relativeFilename);
text.Replace(_T("$DIR"), UnixFilename(fname.GetPath(wxPATH_GET_VOLUME)));
if (bt)
text.Replace(_T("$INCLUDES"),_T("$(") + bt->GetTitle() + _T("_INCS)"));
if (bt)
text.Replace(_T("$CFLAGS"),_T("$(") + bt->GetTitle() + _T("_CFLAGS)"));
if (bt)
text.Replace(_T("$LDFLAGS"),_T("$(") + bt->GetTitle() + _T("_LDFLAGS)"));
if (bt)
text.Replace(_T("$LIBS"),_T("$(") + bt->GetTitle() + _T("_LIBS)"));
if (bt)
text.Replace(_T("$LIBDIRS"),_T("$(") + bt->GetTitle() + _T("_LIBDIRS)"));
text.Replace(_T("$NAME"), UnixFilename(fname.GetName()));
text.Replace(_T("$BASE"), pf->GetBaseName());
text.Replace(_T("$DEPEND_DIR"), d_dir);
text.Replace(_T("$OBJECT_DIR"), o_dir);
text.Replace(_T("$DEPEND"), d_file);
text.Replace(_T("$OBJECT"), o_dir + pf->GetObjName());
text.Replace(_T("$FILENAME"), UnixFilename(pf->relativeFilename));
text.Replace(_T("\n"), _T("\n\t") + m_Quiet);
}
bool MakefileGenerator::CreateMakefile()
{
m_GeneratingMakefile = true;
if (m_CompilerSet->GetSwitches().logging != clogFull)
m_Quiet = _("@");
else
m_Quiet = wxEmptyString;
DoPrepareFiles();
DoPrepareValidTargets();
wxString buffer;
buffer << _T("###############################################################################") << _T('\n');
buffer << _("# Makefile automatically generated by Code::Blocks IDE #") << _T('\n');
buffer << _T("###############################################################################") << _T('\n');
buffer << _T('\n');
buffer << _("# Project: ") << m_Project->GetTitle() << _T('\n');
buffer << _("# Project filename: ") << m_Project->GetFilename() << _T('\n');
// buffer << _T("# Date: ") << wxDateTime::Now().Format("%c", wxDateTime::Local) << _T('\n');
buffer << _("# Compiler used: ") << m_CompilerSet->GetName() << _T('\n');
buffer << _T('\n');
DoAddMakefileVars(buffer);
DoAddMakefileOptions(buffer);
DoAddMakefileCFlags(buffer);
DoAddMakefileLDFlags(buffer);
DoAddMakefileIncludes(buffer);
DoAddMakefileLibDirs(buffer);
DoAddMakefileLibs(buffer);
buffer << _T("###############################################################################") << _T('\n');
buffer << _("# You shouldn't need to modify anything beyond this point #") << _T('\n');
buffer << _T("###############################################################################") << _T('\n');
buffer << _T('\n');
#ifdef __WXMSW__
DoAddMakefileResources(buffer);
#endif // __WXMSW__
DoAddMakefileObjs(buffer);
DoAddMakefileTargets(buffer);
DoAddPhonyTargets(buffer);
DoAddMakefileTarget_All(buffer);
DoAddMakefileTargets_BeforeAfter(buffer);
DoAddMakefileTarget_Dist(buffer);
DoAddMakefileTarget_Clean(buffer);
DoAddMakefileTarget_Depend(buffer);
DoAddMakefileTarget_Link(buffer);
DoAddMakefileTarget_Objs(buffer);
// write Makefile to disk
wxFile file(m_Makefile, wxFile::write);
cbWrite(file,buffer);
m_GeneratingMakefile = false;
return true;
}
syntax highlighted by Code2HTML, v. 0.9.1