/* * 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 * 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 #include "makefilegenerator.h" // class's header file #include #include #include #include #include #include // 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 ") << _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; }