mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
452 lines
13 KiB
C++
452 lines
13 KiB
C++
#include "umake.h"
|
|
|
|
#ifndef bmYEAR
|
|
#include <build_info.h>
|
|
#endif
|
|
|
|
bool SilentMode;
|
|
|
|
String GetUmkFile(const char *fn)
|
|
{
|
|
if(FileExists(fn))
|
|
return NormalizePath(fn);
|
|
if(DirectoryExists(fn) || *fn == '.')
|
|
return Null;
|
|
String h = ConfigFile(fn);
|
|
if(FileExists(h))
|
|
return h;
|
|
String cfgdir = GetFileFolder(GetFileFolder(ConfigFile("x")));
|
|
ONCELOCK
|
|
PutVerbose("Config directory: " << cfgdir);
|
|
return GetFileOnPath(fn,
|
|
cfgdir + "/umk" + ';' +
|
|
cfgdir + "/theide" + ';' +
|
|
cfgdir + "/ide" + ';' +
|
|
GetHomeDirectory() + ';' +
|
|
GetFileFolder(GetExeFilePath()));
|
|
}
|
|
|
|
String GetBuildMethodPath(String method)
|
|
{
|
|
if(GetFileExt(method) != ".bm")
|
|
method << ".bm";
|
|
return GetUmkFile(method);
|
|
}
|
|
|
|
String Ide::GetDefaultMethod()
|
|
{
|
|
return "GCC";
|
|
}
|
|
|
|
String ReplaceMethodDir(String paths, const String& method_dir)
|
|
{
|
|
constexpr const char* METHOD_DIR = "${METHOD_DIR}";
|
|
|
|
if (paths.Find(METHOD_DIR) == -1) {
|
|
return paths;
|
|
}
|
|
paths.Replace(METHOD_DIR, method_dir);
|
|
return paths;
|
|
}
|
|
|
|
VectorMap<String, String> Ide::GetMethodVars(const String& method)
|
|
{
|
|
VectorMap<String, String> map;
|
|
LoadVarFile(GetMethodName(method), map);
|
|
|
|
const String method_dir = GetFileFolder(method);
|
|
const Vector<String> categories_with_method_dir = {"PATH", "INCLUDE", "LIB" };
|
|
for (const auto& category : categories_with_method_dir) {
|
|
map.GetAdd(category) = ReplaceMethodDir(map.Get(category), method_dir);
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
String Ide::GetMethodName(const String& method)
|
|
{
|
|
return GetBuildMethodPath(method);
|
|
}
|
|
|
|
void Puts(const char *s)
|
|
{
|
|
if(!SilentMode)
|
|
Cout() << s;
|
|
}
|
|
|
|
String GetAndroidSDKPath()
|
|
{
|
|
return String();
|
|
}
|
|
|
|
#ifdef flagMAIN
|
|
|
|
String GenerateVersionNumber()
|
|
{
|
|
#ifdef bmGIT_REVCOUNT
|
|
return AsString(atoi(bmGIT_REVCOUNT) + 2270);
|
|
#endif
|
|
return "";
|
|
}
|
|
|
|
CONSOLE_APP_MAIN
|
|
{
|
|
SetConfigName("theide");
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
setlinebuf(stdout);
|
|
CreateBuildMethods();
|
|
#endif
|
|
|
|
Ide ide;
|
|
SetTheIde(&ide);
|
|
ide.console.SetSlots(CPU_Cores());
|
|
ide.console.console = true;
|
|
|
|
ide.debug.def.blitz = ide.release.def.blitz = 0;
|
|
ide.debug.def.debug = 2;
|
|
ide.release.def.debug = 0;
|
|
ide.debug.package.Clear();
|
|
ide.release.package.Clear();
|
|
ide.debug.linkmode = ide.release.linkmode = 0;
|
|
ide.release.createmap = ide.debug.createmap = false;
|
|
ide.targetmode = 0;
|
|
ide.use_target = false;
|
|
ide.makefile_svn_revision = false;
|
|
bool clean = false;
|
|
bool makefile = false;
|
|
bool ccfile = false;
|
|
bool deletedir = true;
|
|
int exporting = 0;
|
|
bool run = false;
|
|
bool auto_hub = false;
|
|
bool update_hub = false;
|
|
bool only_hub = false;
|
|
String hub_dir;
|
|
String out_dir;
|
|
bool flatpak_build = !GetEnv("FLATPAK_ID").IsEmpty();
|
|
String mkf;
|
|
|
|
Vector<String> param, runargs;
|
|
|
|
const Vector<String>& args = CommandLine();
|
|
for(int i = 0; i < args.GetCount(); i++) {
|
|
String a = args[i];
|
|
if(a.StartsWith("--")) {
|
|
String ar = a.Right(a.GetCount() - 2);
|
|
if(ar == "hub-dir") {
|
|
if(i + 1 >= args.GetCount()) {
|
|
Puts("UppHub directory not specified");
|
|
SetExitCode(7);
|
|
return;
|
|
}
|
|
|
|
hub_dir = args[++i];
|
|
}
|
|
else
|
|
if(ar == "hub-only") {
|
|
only_hub = true;
|
|
}
|
|
else
|
|
if(ar == "out-dir") {
|
|
if(i + 1 >= args.GetCount()) {
|
|
Puts("Output directory not specified");
|
|
SetExitCode(7);
|
|
return;
|
|
}
|
|
|
|
out_dir = args[++i];
|
|
}
|
|
else {
|
|
Puts(String("Unrecognized parameter \"") + a + "\".");
|
|
SetExitCode(7);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
if(*a == '-') {
|
|
for(const char *s = ~a + 1; *s; s++)
|
|
switch(*s) {
|
|
case 'a': clean = true; break;
|
|
case 'r': ide.targetmode = 1; break;
|
|
case 'm': ide.release.createmap = ide.debug.createmap = true; break;
|
|
case 'b': ide.release.def.blitz = ide.debug.def.blitz = 1; break;
|
|
case 's': ide.debug.linkmode = ide.release.linkmode = 1; break;
|
|
case 'd': ide.debug.def.debug = 0; break;
|
|
case 'S': ide.debug.linkmode = ide.release.linkmode = 2; break;
|
|
case 'v': ide.console.verbosebuild = true; break;
|
|
case 'l': SilentMode = true; break;
|
|
case 'x': exporting = 1; break;
|
|
case 'X': exporting = 2; break;
|
|
case 'k': deletedir = false; break;
|
|
case 'u': ide.use_target = true; break;
|
|
case 'j': ccfile = true; break;
|
|
case 'h': auto_hub = true; break;
|
|
case 'U': update_hub = true; break;
|
|
case 'M': {
|
|
makefile = true;
|
|
if(s[1] == '=') {
|
|
mkf = NormalizePath(s + 2);
|
|
PutVerbose("Generating Makefile: " + mkf);
|
|
goto endopt;
|
|
}
|
|
else
|
|
PutVerbose("Generating Makefile");
|
|
break;
|
|
}
|
|
case 'H': {
|
|
int n = 0;
|
|
while(IsDigit(s[1])) {
|
|
n = 10 * n + s[1] - '0';
|
|
s++;
|
|
}
|
|
if(!n)
|
|
n = CPU_Cores();
|
|
n = minmax(n, 1, 256);
|
|
PutVerbose("Hydra threads: " + AsString(n));
|
|
ide.console.SetSlots(n);
|
|
break;
|
|
}
|
|
default:
|
|
SilentMode = false;
|
|
Puts("Invalid build option(s)");
|
|
SetExitCode(3);
|
|
return;
|
|
}
|
|
endopt:;
|
|
}
|
|
else
|
|
if(*a == '+')
|
|
ide.mainconfigparam = Filter(~a + 1, [](int c) { return c == ',' ? ' ' : c; });
|
|
else
|
|
if(*a == '!') {
|
|
run = true;
|
|
for(int j = i + 1; j < args.GetCount(); j++)
|
|
runargs.Add(args[j]);
|
|
if(runargs)
|
|
PutVerbose("Set to execute the result with args: " << Join(runargs, " "));
|
|
else
|
|
PutVerbose("Set to execute the result");
|
|
break;
|
|
}
|
|
else
|
|
param.Add(a);
|
|
}
|
|
|
|
UppHubSetupDirForUmk(hub_dir, auto_hub);
|
|
|
|
if(param.GetCount() >= 2) {
|
|
String v = GetUmkFile(param[0] + ".var");
|
|
if(IsNull(v)) {
|
|
#ifdef PLATFORM_POSIX
|
|
Vector<String> h = Split(param[0], [](int c) { return c == ':' || c == ',' ? c : 0; });
|
|
#else
|
|
Vector<String> h = Split(param[0], ',');
|
|
#endif
|
|
for(int i = 0; i < h.GetCount(); i++)
|
|
h[i] = GetFullPath(TrimBoth(h[i]));
|
|
String x = Join(h, ";");
|
|
SetVar("UPP", x, false);
|
|
PutVerbose("Inline assembly: " + x);
|
|
if(out_dir.IsEmpty()) {
|
|
if(flatpak_build)
|
|
out_dir = GetExeFolder() + DIR_SEPS + ".cache" + DIR_SEPS + "upp.out";
|
|
else
|
|
out_dir = GetDefaultUppOut();
|
|
}
|
|
|
|
if(!IsFullPath(out_dir))
|
|
out_dir = GetCurrentDirectory() + DIR_SEPS + out_dir;
|
|
|
|
if(!RealizeDirectory(out_dir)) {
|
|
Puts("Invalid output directory \"" + out_dir + "\".");
|
|
SetExitCode(8);
|
|
return;
|
|
}
|
|
|
|
SetVar("OUTPUT", out_dir, false);
|
|
}
|
|
else {
|
|
if(!LoadVars(v)) {
|
|
Puts("Invalid assembly\n");
|
|
SetExitCode(2);
|
|
return;
|
|
}
|
|
PutVerbose("Assembly file: " + v);
|
|
PutVerbose("Assembly: " + GetVar("UPP"));
|
|
}
|
|
PutVerbose("Output directory: " + GetUppOut());
|
|
ide.main = param[1];
|
|
v = SourcePath(ide.main, GetFileTitle(ide.main) + ".upp");
|
|
PutVerbose("Main package: " + v);
|
|
if(!FileExists(v)) {
|
|
Puts("Package " + ide.main + " does not exist\n");
|
|
SetExitCode(2);
|
|
return;
|
|
}
|
|
if(auto_hub || update_hub) {
|
|
if(!UppHubAuto(ide.main)) {
|
|
SetExitCode(6);
|
|
return;
|
|
}
|
|
if(update_hub)
|
|
UppHubUpdate(ide.main);
|
|
}
|
|
if(only_hub) {
|
|
int exit_code = 0;
|
|
if(!auto_hub && !update_hub) {
|
|
exit_code = 6;
|
|
Puts("The --hub-only option was specified, but UppHub mode instruction are "
|
|
"missing. Please ensure you include the -U or -h flag for the required "
|
|
"UppHub mode configuration.\n");
|
|
}
|
|
SetExitCode(exit_code);
|
|
return;
|
|
}
|
|
ide.wspc.Scan(ide.main);
|
|
const Workspace& wspc = ide.IdeWorkspace();
|
|
if(!wspc.GetCount()) {
|
|
Puts("Empty assembly\n");
|
|
SetExitCode(4);
|
|
return;
|
|
}
|
|
Index<String> missing;
|
|
for(int i = 0; i < wspc.GetCount(); i++) {
|
|
String p = wspc[i];
|
|
if(!FileExists(PackageFile(p)))
|
|
missing.FindAdd(p);
|
|
}
|
|
if(missing.GetCount()) {
|
|
Puts("Missing package(s): " << Join(missing.GetKeys(), " ") << "\n");
|
|
SetExitCode(5);
|
|
return;
|
|
}
|
|
if(IsNull(ide.mainconfigparam)) {
|
|
const Array<Package::Config>& f = wspc.GetPackage(0).config;
|
|
if(f.GetCount())
|
|
ide.mainconfigparam = f[0].param;
|
|
}
|
|
PutVerbose("Build flags: " << ide.mainconfigparam);
|
|
String m = 2 < param.GetCount() ? param[2] : "CLANG";
|
|
String bp = GetBuildMethodPath(m);
|
|
PutVerbose("Build method: " + bp);
|
|
if(bp.GetCount() == 0) {
|
|
SilentMode = false;
|
|
Puts("Invalid build method\n");
|
|
SetExitCode(3);
|
|
return;
|
|
}
|
|
|
|
if(3 < param.GetCount()) {
|
|
ide.debug.target_override = ide.release.target_override = true;
|
|
ide.debug.target = ide.release.target = NormalizePath(param[3]);
|
|
PutVerbose("Target override: " << ide.debug.target);
|
|
}
|
|
|
|
ide.method = bp;
|
|
|
|
if(ccfile) {
|
|
ide.SaveCCJ(GetFileDirectory(PackageFile(ide.main)) + "compile_commands.json", false);
|
|
SetExitCode(0);
|
|
return;
|
|
}
|
|
|
|
if(clean)
|
|
ide.Clean();
|
|
if(exporting) {
|
|
mkf = GetFullPath(mkf);
|
|
Cout() << mkf << '\n';
|
|
RealizeDirectory(mkf);
|
|
if(makefile)
|
|
ide.ExportMakefile(mkf);
|
|
else
|
|
ide.ExportProject(mkf, exporting == 2, deletedir);
|
|
}
|
|
else
|
|
if(makefile) {
|
|
ide.SaveMakeFile(IsNull(mkf) ? "Makefile" : mkf, false);
|
|
SetExitCode(0);
|
|
}
|
|
else
|
|
if(ide.Build()) {
|
|
SetExitCode(0);
|
|
if(run) {
|
|
Vector<char *> args;
|
|
Vector<Buffer<char>> buffer;
|
|
auto Add = [&](const String& s) {
|
|
auto& b = buffer.Add();
|
|
b.Alloc(s.GetCount() + 1);
|
|
memcpy(b, s, s.GetCount() + 1);
|
|
args.Add(b);
|
|
};
|
|
Add(ide.target);
|
|
for(const String& s : runargs)
|
|
Add(s);
|
|
args.Add(NULL);
|
|
SetExitCode((int)execv(ide.target, args.begin()));
|
|
}
|
|
}
|
|
else
|
|
SetExitCode(1);
|
|
}
|
|
else {
|
|
String version = GenerateVersionNumber();
|
|
Puts("umk (U++MaKe) " + version + "\n\n"
|
|
"Usage:\n"
|
|
" umk assembly package [build_method] [--hub-dir dir] [--hub-only] [-options] [+flags] [out]\n"
|
|
" [! [runarg]..]\n\n"
|
|
"Arguments:\n"
|
|
" assembly - is a direct set of package nest directories relative to working directory that\n"
|
|
" represent U++ assembly separated by ','.\n"
|
|
" package - is the main package (a program to build).\n"
|
|
" build_method - is build method that is to be used to build the resulting executable. If not\n"
|
|
" specified, CLANG build method is assumed. Note that in POSIX, umk automatically\n"
|
|
" creates CLANG and GCC build methods if they do not exist.\n"
|
|
" Optional parameters:\n"
|
|
" --hub-dir - specifies the directory where UppHub packages should be downloaded, using\n"
|
|
" the second parameter, dir, to set the path.\n"
|
|
" --hub-only - instructs UMK to handle only the logic related to UppHub.\n"
|
|
" --out-dir - specifies the directory where UMK stores build artifacts,\n"
|
|
" using the second parameter, dir, to define the path.\n"
|
|
" Additional options [-options for example -brU]:\n"
|
|
" a - rebuild all.\n"
|
|
" b - use BLITZ.\n"
|
|
" l - silent mode.\n"
|
|
" u - use target directory.\n"
|
|
" m - create a map file.\n"
|
|
" r - release mode.\n"
|
|
" d - debug mode without debug symbols.\n"
|
|
" s - use shared libraries.\n"
|
|
" S - use shared libraries and build as shared libraries.\n"
|
|
" v - be verbose\n"
|
|
" M - create makefile (to file Makefile)\n"
|
|
" M=makefile - create makefile with given name.\n"
|
|
" Hn - number of threads used for build. Default is number of logical cores available.\n"
|
|
" h - enables downloading missing packages from UppHub. This command removes any other\n"
|
|
" UppHub packages if exists.\n"
|
|
" U - Install missing packages from UppHub and update all UppHub nests to the latest versions.\n"
|
|
" Do not delete any existing UppHub packages.\n"
|
|
" j - generate compile_commands.json\n"
|
|
" x - export projects sources and documentation\n"
|
|
" X - export entire project\n"
|
|
" k - delete target directory before project export\n\n"
|
|
" If none of the above options are provided, a debug build with symbols will be executed\n"
|
|
" by default.\n"
|
|
" flags - are compilation flags. If flags are not specified, the first main configuration\n"
|
|
" entry in .upp file is used by default. Use commas to chain multiple flags,\n"
|
|
" such as +GUI,SHARED.\n"
|
|
" out - overrides output name, file or directory.\n"
|
|
" ! - means the the resulting binary should be also executed after successful build, using\n"
|
|
" optional arguments after ! as its arguments.\n"
|
|
"\nExamples:\n"
|
|
" Basic:\n"
|
|
" umk examples Bombs CLANG -ab +GUI,SHARED ~/bombs\n"
|
|
" umk ~/upp.src/examples,~/upp.src/uppsrc Bombs ~/GCC.bm -rv +GUI,SHARED ~/bin\n"
|
|
" umk ./,3p/uppsrc UppTerm 3p/umk/CLANG.bm --hub-dir 3p/hub -brU +GUI,SHARED build/UppTerm\n\n"
|
|
" Below is an example of how to download UppHub dependencies without triggering a build:\n"
|
|
" umk ./,3p/uppsrc UppTerm 3p/umk/CLANG.bm --hub-dir 3p/hub --hub-only -U\n\n"
|
|
"See https://www.ultimatepp.org/app$ide$umk$en-us.html for more details.\n");
|
|
}
|
|
}
|
|
|
|
#endif
|