diff --git a/uppsrc/ide/Browser/TopicWin.cpp b/uppsrc/ide/Browser/TopicWin.cpp index e76cb4852..2d619d798 100644 --- a/uppsrc/ide/Browser/TopicWin.cpp +++ b/uppsrc/ide/Browser/TopicWin.cpp @@ -127,6 +127,22 @@ void TopicEditor::ExportGroupPdf() } } +String MakeHtml(const char *title, String css, String body) +{ + String h = + "\r\n" + "\t\n" + "\t\n" + "\t\n" + "" + String(title) + "\r\n" + ; + if(!IsNull(css)) + h << "\r\n"; + h << "" << body << ""; + return h; +} + void TopicEditor::ExportHTML() { String path = SelectFileSaveAs("HTML files\t*.html\nAll files\t*.*"); @@ -136,7 +152,7 @@ void TopicEditor::ExportHTML() String html = EncodeHtml(editor.Get(), css, VectorMap(), VectorMap(), GetFileFolder(path)); - SaveFile(path, HtmlHeader((String)~title, AsCss(css)) / html); + SaveFile(path, MakeHtml((String)~title, AsCss(css), html)); // SaveFile(ForceExt(path, ".css"), AsCss(css)); } @@ -154,7 +170,7 @@ void TopicEditor::ExportGroupHTML() String html = EncodeHtml(ParseQTF(t.text), css, VectorMap(), VectorMap(), dir); - html = HtmlHeader(t.title, AsCss(css)) / html; + html = MakeHtml(t.title, AsCss(css), html); String path = AppendFileName(dir, GetFileTitle(ff.GetName()) + ".html"); if(LoadFile(path) != html) SaveFile(path, html); diff --git a/uppsrc/ide/Builders/Build.cpp b/uppsrc/ide/Builders/Build.cpp index 015b9b86c..8cc06dc0b 100644 --- a/uppsrc/ide/Builders/Build.cpp +++ b/uppsrc/ide/Builders/Build.cpp @@ -1,744 +1,749 @@ -#include "Builders.h" - -#include - -#define LDUMP(x) // DUMP(x) - -MakeBuild::MakeBuild() -{ - targetmode = 0; - stoponerrors = true; - use_target = false; -} - -const TargetMode& MakeBuild::GetTargetMode() -{ - return (targetmode == 0 ? debug : release); -} - -Index MakeBuild::PackageConfig(const Workspace& wspc, int package, - const VectorMap& bm, String mainparam, - Host& host, Builder& b, String *target) -{ - String packagepath = PackagePath(wspc[package]); - const Package& pkg = wspc.package[package]; - Index cfg; - mainparam << ' ' << bm.Get(targetmode ? "RELEASE_FLAGS" : "DEBUG_FLAGS", NULL); - cfg = SplitFlags(mainparam, package == 0, wspc.GetAllAccepts(package)); - cfg.FindAdd(bm.Get("BUILDER", "GCC")); - const TargetMode& m = GetTargetMode(); - if(targetmode == 0) - cfg.FindAdd("DEBUG"); - switch(m.linkmode) { - case 2: - cfg.FindAdd("SO"); - case 1: - cfg.FindAdd("SHARED"); - } - if(targetmode == 2) - cfg.FindAdd("FORCE_SPEED"); - if(targetmode == 3) - cfg.FindAdd("FORCE_SIZE"); - int q = m.package.Find(wspc[package]); - if(q >= 0) { - const PackageMode& p = m.package[q]; - switch(p.debug >= 0 ? p.debug : m.def.debug) { - case 1: cfg.FindAdd("DEBUG_MINIMAL"); break; - case 2: cfg.FindAdd("DEBUG_FULL"); break; - } - if(!pkg.noblitz && (p.blitz >= 0 ? p.blitz : m.def.blitz)) - cfg.FindAdd("BLITZ"); - } - else { - switch(m.def.debug) { - case 1: cfg.FindAdd("DEBUG_MINIMAL"); break; - case 2: cfg.FindAdd("DEBUG_FULL"); break; - } - if(!pkg.noblitz && m.def.blitz) - cfg.FindAdd("BLITZ"); - } - host.AddFlags(cfg); - b.AddFlags(cfg); - for(int i = 0; i < pkg.flag.GetCount(); i++) { - if(MatchWhen(pkg.flag[i].when, cfg.GetKeys())) - cfg.Add(pkg.flag[i].text); - } - if(target) - *target = Gather(pkg.target, cfg.GetKeys(), true); - return cfg; -} - -String NoCr(const char *s) -{ - String out; - while(*s) - { - const char *b = s; - while(*s && *s != '\r') - s++; - out.Cat(b, int(s - b)); - if(*s == '\r') - s++; - } - return out; -} - -bool MakeBuild::SyncHostFiles(RemoteHost& host) -{ - HdependTimeDirty(); - String query = "<"; -// Vector remotepath; - Vector fdata; - ArrayMap info; - Vector nocrsize; - const Workspace& wspc = GetIdeWorkspace(); - int p; - for(p = 0; p < wspc.GetCount(); p++) { - const Package& pkg = wspc.GetPackage(p); - String pn = wspc[p]; - for(int f = -1; f < pkg.file.GetCount(); f++) - if(f < 0 || !pkg.file[f].separator) { - Vector pkgfiles; - String pk = (f >= 0 ? SourcePath(pn, pkg.file[f]) : PackagePath(pn)); - if(!FindFile(pk).IsFile()) - continue; - pkgfiles.Add(f >= 0 ? SourcePath(pn, pkg.file[f]) : PackagePath(pn)); - pkgfiles.AppendPick(HdependGetDependencies(pkgfiles[0])); - for(int d = 0; d < pkgfiles.GetCount(); d++) { - TransferFileInfo newinfo; - newinfo.sourcepath = pkgfiles[d]; - String rp = host.GetHostPath(newinfo.sourcepath); - if(info.Find(rp) >= 0 || (d && UnixPath(rp) == UnixPath(newinfo.sourcepath))) - continue; - FindFile ff(newinfo.sourcepath); - newinfo.filetime = (int)(Time(ff.GetLastWriteTime()) - RemoteHost::TimeBase()); - newinfo.filesize = (int)ff.GetLength(); - int pos = transferfilecache.Find(rp); - if(pos < 0 || transferfilecache[pos].filetime != newinfo.filetime - || transferfilecache[pos].filesize != newinfo.filesize) - { - String content = NoCr(LoadFile(newinfo.sourcepath)); - query << rp << '\t' << newinfo.filetime << '\t' << content.GetLength() << '\n'; - // remotepath.Add(rp); - fdata.Add(content); - info.Add(rp, newinfo); - nocrsize.Add(content.GetLength()); - PutVerbose("Checking remote " + rp); - /* - if(msecs(ticks) >= 0) - { - ShowConsole(); - console.Sync(); - ticks = msecs(-200); - } - */ } - } - } - } - if(info.IsEmpty()) - return true; -// String host = GetVar("REMOTE_HOST"); -// int port = 2346; -// int ppos = host.Find(':'); -// if(ppos >= 0) -// { -// port = ScanInt(host.GetIter(ppos + 1)); -// host.Trim(ppos); -// } - - Index ignore; - { - PutConsole(NFormat("Retrieving update list for remote filesystem %s", host.host)); - ConsoleShow(); - String out = host.RemoteExec(query); - if(out[0] != 'O' || out[1] != 'K') { - PutConsole(out); - return false; - } - - const char *s = out; - while(*s && *s++ != '\n') - ; - while(*s) - { - const char *b = s; - while(*s && *s != '\n') - s++; - ignore.FindAdd(NormalizePath(NativePath(String(b, s)))); - if(*s) - s++; - } - if(ignore.GetCount() == info.GetCount()) - PutConsole("Remote source tree is up to date."); - else - { - PutConsole(NFormat("%d file(s) missing in remote source tree:", info.GetCount() - ignore.GetCount())); - for(p = 0; p < info.GetCount(); p++) - { -// console << " " << remotepath[p] << " - " -// << FormatInt(p) << " @ " << FormatInt(ignore.Find(remotepath[p])) << "\n"; - if(ignore.Find(NormalizePath(NativePath(info.GetKey(p)))) < 0) - PutConsole(String().Cat() << " " << info.GetKey(p)); - } - } - } - - Vector update; - for(p = 0; p < info.GetCount(); p++) - if(ignore.Find(NormalizePath(NativePath(info.GetKey(p)))) < 0) - { - String rawdata = fdata[p]; - PutConsole(String().Cat() << "Compressing " << info[p].sourcepath << " (" << FormatInt(rawdata.GetLength()) << " B)\n"); - ConsoleSync(); - String bzdata = BZ2Compress(rawdata); - String comp = ASCII85Encode(bzdata); - if(update.IsEmpty() || update.Top().GetLength() + comp.GetLength() >= 500000) - update.Add(">"); - update.Top() << info.GetKey(p) << '\t' << info[p].filetime << '\t' << nocrsize[p] << '\t' << comp << '\n'; - } - - for(p = 0; p < update.GetCount(); p++) - { - PutConsole(NFormat("Uploading block %d / %d (%d B)", p + 1, update.GetCount(), update[p].GetLength())); - ConsoleShow(); - String result = host.RemoteExec(update[p]); - if(result[0] != 'O' || result[1] != 'K') { - PutConsole(result); - return false; - } - } - - for(p = 0; p < info.GetCount(); p++) - transferfilecache.GetAdd(info.GetKey(p)) = info[p]; - return true; -} - -One MakeBuild::CreateHost(bool sync_files) -{ - SetupDefaultMethod(); - VectorMap bm = GetMethodVars(method); - String rm = bm.Get("REMOTE_HOST", Null); - One outhost; - if(!IsNull(rm)) { - One host = new RemoteHost; - host->host = rm; - host->port = 2346; - int f = rm.Find(':'); - if(f >= 0) { - host->host = rm.Left(f); - host->port = Nvl(ScanInt(rm.GetIter(f + 1)), host->port); - } - host->os_type = bm.Get("REMOTE_OS", "UNIX"); - Vector path_map = Split(bm.Get("REMOTE_MAP", Null), ';'); - for(int p = 0; p < path_map.GetCount(); p++) { - f = path_map[p].Find('>'); - if(f >= 0) { - host->path_map_local.Add(path_map[p].Left(f)); - host->path_map_remote.Add(path_map[p].Mid(f + 1)); - } - } - VectorMap env(Environment(), 1); - Vector exedirs = SplitDirs(bm.Get("PATH", "") + ';' + env.Get("PATH", "")); - env.GetAdd("PATH") = Join(exedirs, ";"); - for(int i = 0; i < env.GetCount(); i++) - host->environment << env.GetKey(i) << '=' << env[i] << '\0'; - host->environment.Cat(0); - if(sync_files && bm.Get("REMOTE_TRANSFER", Null) != "0") - SyncHostFiles(*host); - outhost = -host; - } - else { - One host = new LocalHost; - VectorMap env(Environment(), 1); - host->exedirs = SplitDirs(bm.Get("PATH", "") + ';' + env.Get("PATH", "")); - env.GetAdd("PATH") = Join(host->exedirs, ";"); - env.GetAdd("UPP_MAIN__") = GetFileDirectory(PackagePath(GetMain())); - env.GetAdd("UPP_ASSEMBLY__") = GetVar("UPP"); - for(int i = 0; i < env.GetCount(); i++) { - LDUMP(env.GetKey(i)); - LDUMP(env[i]); - host->environment << env.GetKey(i) << '=' << env[i] << '\0'; - } - host->environment.Cat(0); - host->cmdout = &cmdout; - outhost = -host; - } - return outhost; -} - -One MakeBuild::CreateBuilder(Host *host) -{ - SetupDefaultMethod(); - VectorMap bm = GetMethodVars(method); - String builder = bm.Get("BUILDER", "GCC"); - int q = BuilderMap().Find(builder); - if(q < 0) { - PutConsole("Invalid builder " + builder); - ConsoleShow(); - return NULL; - } - One b = (*BuilderMap().Get(builder))(); - b->host = host; - b->compiler = bm.Get("COMPILER", ""); - b->include = SplitDirs(GetVar("UPP") + ';' + bm.Get("INCLUDE", "")); - const Workspace& wspc = GetIdeWorkspace(); - for(int i = 0; i < wspc.GetCount(); i++) { - const Package& pkg = wspc.GetPackage(i); - for(int j = 0; j < pkg.include.GetCount(); j++) - b->include.Add(SourcePath(wspc[i], pkg.include[j].text)); - } - b->libpath = SplitDirs(bm.Get("LIB", "")); - b->debug_options = bm.Get("DEBUG_OPTIONS", ""); - b->release_options = bm.Get("RELEASE_OPTIONS", ""); - b->release_size_options = bm.Get("RELEASE_SIZE_OPTIONS", ""); - b->debug_link = bm.Get("DEBUG_LINK", ""); - b->release_link = bm.Get("RELEASE_LINK", ""); - b->script = bm.Get("SCRIPT", ""); - return b; -} - -int CharFilterSlash(int c) -{ - return c == '\\' ? '/' : c; -} - -bool output_per_assembly; - -String MakeBuild::OutDir(const Index& cfg, const String& package, const VectorMap& bm, - bool use_target) -{ - Index excl; - excl.Add(bm.Get("BUILDER", "GCC")); - excl.Add("MSC"); - LocalHost().AddFlags(excl); - Vector x; - bool dbg = cfg.Find("DEBUG_FULL") >= 0 || cfg.Find("DEBUG_MINIMAL") >= 0; - if(cfg.Find("DEBUG") >= 0) { - excl.Add("BLITZ"); - if(cfg.Find("BLITZ") < 0) - x.Add("NOBLITZ"); - } - else - if(dbg) - x.Add("RELEASE"); - if(use_target) - excl.Add("MAIN"); - for(int i = 0; i < cfg.GetCount(); i++) - if(excl.Find(cfg[i]) < 0) - x.Add(cfg[i]); - Sort(x); - for(int i = 0; i < x.GetCount(); i++) - x[i] = InitCaps(x[i]); - String outdir = GetVar("OUTPUT"); - if(output_per_assembly) - outdir = AppendFileName(outdir, GetVarsName()); - if(!use_target) - outdir = AppendFileName(outdir, package); - outdir = AppendFileName(outdir, GetFileTitle(method) + "." + Join(x, ".")); - outdir = Filter(outdir, CharFilterSlash); - return outdir; -} - -struct OneFileHost : Host { - One host; - String onefile; - - virtual String GetEnvironment() { return host->GetEnvironment(); } - virtual String GetHostPath(const String& path) { return host->GetHostPath(path); } - virtual String GetLocalPath(const String& path) { return host->GetLocalPath(path); } - virtual String NormalizePath(const String& path) { return host->NormalizePath(path); } - virtual void DeleteFile(const Vector& path) { host->DeleteFile(path); } - virtual void DeleteFolderDeep(const String& folder) { host->DeleteFolderDeep(folder); } - virtual void ChDir(const String& path) { host->ChDir(path); } - virtual void RealizeDir(const String& path) { host->RealizeDir(path); } - virtual void SaveFile(const String& path, const String& data) { host->SaveFile(path, data); } - virtual String LoadFile(const String& path) { return host->LoadFile(path); } - virtual int Execute(const char *c) { return host->Execute(c); } - virtual int ExecuteWithInput(const char *c) { return host->ExecuteWithInput(c); } - virtual int Execute(const char *c, Stream& o) { return host->Execute(c, o); } - virtual int AllocSlot() { return host->AllocSlot(); } - virtual bool Run(const char *cmdline, int slot, String key, int blitz_count) { return host->Run(cmdline, slot, key, blitz_count); } - virtual bool Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) { return host->Run(cmdline, out, slot, key, blitz_count); } - virtual bool Wait() { return host->Wait(); } - virtual One StartProcess(const char *c) { return host->StartProcess(c); } - virtual void Launch(const char *cmdline, bool) { host->Launch(cmdline); } - virtual void AddFlags(Index& cfg) { host->AddFlags(cfg); } - - virtual Vector GetFileInfo(const Vector& path) { - Vector fi = host->GetFileInfo(path); - for(int i = 0; i < path.GetCount(); i++) - if(path[i] == onefile) - (Time &)fi[i] = GetSysTime(); - else - (Time &)fi[i] = Time::Low(); - return fi; - } -}; - -bool MakeBuild::BuildPackage(const Workspace& wspc, int pkindex, int pknumber, int pkcount, - String mainparam, String outfile, Vector& linkfile, String& linkopt, bool link) -{ - String package = wspc[pkindex]; - String mainpackage = wspc[0]; - const Package& pkg = wspc.package[pkindex]; - VectorMap bm = GetMethodVars(method); - if(bm.GetCount() == 0) { - PutConsole("Invalid build method"); - ConsoleShow(); - return false; - } - One host = CreateHost(false); - if(!IsNull(onefile)) { - OneFileHost *h = new OneFileHost; - h->host = host; - h->onefile = onefile; - host = h; - } - One b = CreateBuilder(~host); - if(!b) - return false; - b->config = PackageConfig(wspc, pkindex, bm, mainparam, *host, *b); - const TargetMode& m = targetmode == 0 ? debug : release; - b->version = m.version; - b->method = method; - b->outdir = OutDir(b->config, package, bm); - host->RealizeDir(b->outdir); - String mainfn = Null; - Index mcfg = PackageConfig(wspc, 0, bm, mainparam, *host, *b, &mainfn); - HdependClearDependencies(); - for(int i = 0; i < pkg.GetCount(); i++) { - const Array& f = pkg[i].depends; - for(int j = 0; j < f.GetCount(); j++) - if(MatchWhen(f[j].when, mcfg.GetKeys())) - HdependAddDependency(SourcePath(package, pkg[i]), SourcePath(package, f[j].text)); - } - String tout = OutDir(mcfg, mainpackage, bm, use_target); - host->RealizeDir(tout); - if(IsNull(mainfn)) - mainfn = GetFileTitle(mainpackage) + b->GetTargetExt(); - if(!IsNull(outfile)) - target = NormalizePath(outfile, tout); - else { - if(m.target_override && !IsNull(m.target) && IsFolder(m.target)) - target = host->NormalizePath(AppendFileName(m.target, mainfn)); - else - if(m.target_override && (IsFullPath(m.target) || *m.target == '/' || *m.target == '\\')) - target = m.target; - else - if(m.target_override && !IsNull(m.target)) - target = host->NormalizePath(AppendFileName(tout, m.target)); - else - if(IsFullPath(mainfn)) - target = mainfn; - else - target = host->NormalizePath(AppendFileName(tout, mainfn)); - } - b->target = target; - b->mainpackage = mainpackage; - if(IsNull(onefile)) { - String out; - out << "----- " << package << " ( " << Join(b->config.GetKeys(), " ") << " )"; - if(pkcount > 1) - out << " (" << (pknumber + 1) << " / " << pkcount << ')'; - PutConsole(out); - } - else - b->config.FindAdd("NOLIB"); - bool ok = b->BuildPackage(package, linkfile, linkopt, - GetAllUses(wspc, pkindex), - GetAllLibraries(wspc, pkindex, bm, mainparam, *host, *b), - targetmode - 1); - Vector errors = PickErrors(); - host->DeleteFile(errors); - if(!ok || !errors.IsEmpty()) - return false; - if(link) { - ok = b->Link(linkfile, linkopt, GetTargetMode().createmap); - errors = PickErrors(); - host->DeleteFile(errors); - if(!ok || !errors.IsEmpty()) - return false; - } - return true; -} - -void MakeBuild::SetHdependDirs() -{ - Vector include = SplitDirs(GetVar("UPP") + ';' - + GetMethodVars(method).Get("INCLUDE", "") + ';' - + Environment().Get("INCLUDE", "") -#ifdef PLATFORM_POSIX - + ";/usr/include;/usr/local/include" -#endif - ); - // Also adding internal includes - const Workspace& wspc = GetIdeWorkspace(); - for(int i = 0; i < wspc.GetCount(); i++) { - const Package& pkg = wspc.GetPackage(i); - for(int j = 0; j < pkg.include.GetCount(); j++) - include.Add(SourcePath(wspc[i], pkg.include[j].text)); - } - - HdependSetDirs(include); -} - -Vector MakeBuild::GetAllUses(const Workspace& wspc, int f) -{ // Warning: This does not seem to do what it is supposed to do... - String package = wspc[f]; - Index all_uses; - bool warn = true; - int n = 0; - while(f >= 0) { - const Package& p = wspc.package[f]; - for(int fu = 0; fu < p.uses.GetCount(); fu++) - if(p.uses[fu].text != package) - all_uses.FindAdd(p.uses[fu].text); - else if(warn) { - PutConsole(NFormat("%s: circular 'uses' chain", package)); - warn = false; - } - f = -1; - while(n < all_uses.GetCount() && (f = wspc.package.Find(all_uses[n++])) < 0) - ; - } - return all_uses.PickKeys(); -} - -Vector MakeBuild::GetAllLibraries(const Workspace& wspc, int index, - const VectorMap& bm, String mainparam, - Host& host, Builder& builder) -{ // Warning: This does not seem to do what it is supposed to do... - Vector uses = GetAllUses(wspc, index); - uses.Add(wspc[index]); - Index libraries; - - for(int i = 0; i < uses.GetCount(); i++) { - int f = wspc.package.Find(UnixPath(uses[i])); - if(f >= 0) { - const Package& pk = wspc.package[f]; - Index config = PackageConfig(wspc, f, bm, mainparam, host, builder); - Vector pklibs = Split(Gather(pk.library, config.GetKeys()), ' '); - FindAppend(libraries, pklibs); - } - } - return libraries.PickKeys(); -} - -bool MakeBuild::Build(const Workspace& wspc, String mainparam, String outfile, bool clear_console) -{ - ClearErrorEditor(); - BeginBuilding(true, clear_console); - bool ok = true; - if(wspc.GetCount()) { - Vector build_order; - if(GetTargetMode().linkmode != 2) { - for(int i = 1; i < wspc.GetCount(); i++) - build_order.Add(i); - } - else { - Index remaining; - for(int i = 1; i < wspc.GetCount(); i++) - remaining.Add(i); - while(!remaining.IsEmpty()) { - int t; - for(t = 0; t < remaining.GetCount(); t++) { - const Package& pk = wspc.package[remaining[t]]; - bool delay = false; - for(int u = 0; u < pk.uses.GetCount(); u++) - if(remaining.Find(wspc.package.Find(pk.uses[u].text)) >= 0) { - delay = true; - break; - } - if(!delay) - break; - } - if(t >= remaining.GetCount()) - t = 0; - build_order.Add(remaining[t]); - remaining.Remove(t); - } - } - String mainpackage = wspc[0]; - Vector linkfile; - String linkopt = GetMethodVars(method).Get(targetmode ? "RELEASE_LINK" : "DEBUG_LINK", Null); - if(linkopt.GetCount()) - linkopt << ' '; - ok = true; - int ms = msecs(); - for(int i = 0; i < build_order.GetCount() && (ok || !stoponerrors); i++) { - int px = build_order[i]; - ok = BuildPackage(wspc, px, i, build_order.GetCount() + 1, - mainparam, Null, linkfile, linkopt) && ok; - if(msecs() - ms >= 200) { - DoProcessEvents(); - ms = msecs(); - } - } - if(ok || !stoponerrors) - ok = BuildPackage(wspc, 0, build_order.GetCount(), build_order.GetCount() + 1, - mainparam, outfile, linkfile, linkopt, ok) && ok; - } - EndBuilding(ok); - ReQualifyCodeBase(); - SetErrorEditor(); - return ok; -} - -bool MakeBuild::Build() -{ - VectorMap bm = GetMethodVars(method); - if(bm.GetCount() == 0) { - PutConsole("Invalid build method"); - ConsoleShow(); - return false; - } - One host = CreateHost(false); - One builder = CreateBuilder(~host); - if(!builder) - return false; - Index p = PackageConfig(GetIdeWorkspace(), 0, bm, mainconfigparam, - *host, *builder); - Workspace wspc; - wspc.Scan(GetMain(), p.GetKeys()); - return Build(wspc, mainconfigparam, Null); -} - -void MakeBuild::CleanPackage(const Workspace& wspc, int package) -{ - PutConsole(NFormat("Cleaning %s", wspc[package])); - One host = CreateHost(false); - One builder = CreateBuilder(~host); - if(!builder) - return; - host->DeleteFolderDeep(OutDir(PackageConfig(wspc, package, GetMethodVars(method), mainconfigparam, - *host, *builder), wspc[package], GetMethodVars(method))); -} - -void MakeBuild::Clean() -{ - ConsoleClear(); - const Workspace& wspc = GetIdeWorkspace(); - for(int i = 0; i < wspc.GetCount(); i++) - CleanPackage(wspc, i); - PutConsole("...done"); -} - -void MakeBuild::RebuildAll() -{ - Clean(); - Build(); -} - -void MakeBuild::SaveMakeFile(const String& fn, bool exporting) -{ - BeginBuilding(false, true); - - VectorMap bm = GetMethodVars(method); - One host = CreateHost(false); - One b = CreateBuilder(~host); - - if(!b) - return; - - const TargetMode& tm = GetTargetMode(); - - String makefile; - - Vector uppdirs = GetUppDirs(); - String uppout = exporting ? host->GetHostPath(GetVar("OUTPUT")) : "_out/"; - String inclist; - - Index allconfig = PackageConfig(GetIdeWorkspace(), 0, bm, mainconfigparam, *host, *b); - bool win32 = allconfig.Find("WIN32") >= 0; - - Workspace wspc; - wspc.Scan(GetMain(), allconfig.GetKeys()); - - for(int i = 1; i < wspc.GetCount(); i++) { - Index modconfig = PackageConfig(wspc, i, bm, mainconfigparam, *host, *b); - for(int a = allconfig.GetCount(); --a >= 0;) - if(modconfig.Find(allconfig[a]) < 0) - allconfig.Remove(a); - } - - if(!exporting) - for(int i = 0; i < uppdirs.GetCount(); i++) { - String srcdir = GetMakePath(AdjustMakePath(host->GetHostPath(AppendFileName(uppdirs[i], ""))), win32); - makefile << "UPPDIR" << (i + 1) << " = " << srcdir << "\n"; - inclist << " -I$(UPPDIR" << (i + 1) << ")"; - } - else - inclist << "-I./"; - Vector includes = SplitDirs(bm.Get("INCLUDE","")); - for(int i = 0; i < includes.GetCount(); i++) - inclist << " -I" << includes[i]; - - makefile << "\n" - "UPPOUT = " << (exporting ? "_out/" : GetMakePath(AdjustMakePath(host->GetHostPath(AppendFileName(uppout, ""))), win32)) << "\n" - "CINC = " << inclist << "\n" - "Macro = "; - - for(int i = 0; i < allconfig.GetCount(); i++) - makefile << " -Dflag" << allconfig[i]; - makefile << "\n"; - - String output, config, install, rules, linkdep, linkfiles, linkfileend; - - for(int i = 0; i < wspc.GetCount(); i++) { - b->config = PackageConfig(wspc, i, bm, mainconfigparam, *host, *b); - b->version = tm.version; - b->method = method; - MakeFile mf; - b->AddMakeFile(mf, wspc[i], GetAllUses(wspc, i), - GetAllLibraries(wspc, i, bm, mainconfigparam, *host, *b), allconfig, - exporting); - if(!i) { - String tdir = mf.outdir; - String trg; - if(tm.target_override) { - trg = GetMakePath(AdjustMakePath(tm.target), win32); - if(!trg.IsEmpty() && *trg.Last() == (win32 ? '\\' : '/')) - trg << mf.outfile; - else if(trg.Find(win32 ? '\\' : '/') < 0) - trg.Insert(0, "$(OutDir)"); - } - output = Nvl(trg, mf.output); - if(exporting) - output = wspc[i] + ".out"; - install << "\n" - "OutDir = " << tdir << "\n" - "OutFile = " << output << "\n" - "\n" - ".PHONY: all\n" - "all: prepare $(OutFile)\n" - "\n" - ".PHONY: prepare\n" - "prepare:\n"; - } - config << mf.config; - install << mf.install; - rules << mf.rules; - linkdep << mf.linkdep; - linkfiles << mf.linkfiles; - linkfileend << mf.linkfileend; - } - - makefile - << config - << install - << "\n" - "$(OutFile): " << linkdep << "\n\t" << linkfiles << linkfileend << " -Wl,--end-group\n\n" - << rules - << ".PHONY: clean\n" - << "clean:\n" - << "\tif [ -d $(UPPOUT) ]; then rm -rf $(UPPOUT); fi;\n"; - - bool sv = ::SaveFile(fn, makefile); - if(!exporting) - if(sv) - PutConsole(NFormat("%s(1): makefile generation complete", fn)); - else - PutConsole(NFormat("%s: error writing makefile", fn)); - - EndBuilding(true); -} +#include "Builders.h" + +#include + +#define LDUMP(x) // DUMP(x) + +MakeBuild::MakeBuild() +{ + targetmode = 0; + stoponerrors = true; + use_target = false; +} + +const TargetMode& MakeBuild::GetTargetMode() +{ + return (targetmode == 0 ? debug : release); +} + +Index MakeBuild::PackageConfig(const Workspace& wspc, int package, + const VectorMap& bm, String mainparam, + Host& host, Builder& b, String *target) +{ + String packagepath = PackagePath(wspc[package]); + const Package& pkg = wspc.package[package]; + Index cfg; + mainparam << ' ' << bm.Get(targetmode ? "RELEASE_FLAGS" : "DEBUG_FLAGS", NULL); + cfg = SplitFlags(mainparam, package == 0, wspc.GetAllAccepts(package)); + cfg.FindAdd(bm.Get("BUILDER", "GCC")); + const TargetMode& m = GetTargetMode(); + if(targetmode == 0) + cfg.FindAdd("DEBUG"); + switch(m.linkmode) { + case 2: + cfg.FindAdd("SO"); + case 1: + cfg.FindAdd("SHARED"); + } + if(targetmode == 2) + cfg.FindAdd("FORCE_SPEED"); + if(targetmode == 3) + cfg.FindAdd("FORCE_SIZE"); + int q = m.package.Find(wspc[package]); + if(q >= 0) { + const PackageMode& p = m.package[q]; + switch(p.debug >= 0 ? p.debug : m.def.debug) { + case 1: cfg.FindAdd("DEBUG_MINIMAL"); break; + case 2: cfg.FindAdd("DEBUG_FULL"); break; + } + if(!pkg.noblitz && (p.blitz >= 0 ? p.blitz : m.def.blitz)) + cfg.FindAdd("BLITZ"); + } + else { + switch(m.def.debug) { + case 1: cfg.FindAdd("DEBUG_MINIMAL"); break; + case 2: cfg.FindAdd("DEBUG_FULL"); break; + } + if(!pkg.noblitz && m.def.blitz) + cfg.FindAdd("BLITZ"); + } + host.AddFlags(cfg); + b.AddFlags(cfg); + for(int i = 0; i < pkg.flag.GetCount(); i++) { + if(MatchWhen(pkg.flag[i].when, cfg.GetKeys())) + cfg.Add(pkg.flag[i].text); + } + if(target) + *target = Gather(pkg.target, cfg.GetKeys(), true); + return cfg; +} + +String NoCr(const char *s) +{ + String out; + while(*s) + { + const char *b = s; + while(*s && *s != '\r') + s++; + out.Cat(b, int(s - b)); + if(*s == '\r') + s++; + } + return out; +} + +#if 0 // REMOTE REMOVED +bool MakeBuild::SyncHostFiles(RemoteHost& host) +{ + HdependTimeDirty(); + String query = "<"; +// Vector remotepath; + Vector fdata; + ArrayMap info; + Vector nocrsize; + const Workspace& wspc = GetIdeWorkspace(); + int p; + for(p = 0; p < wspc.GetCount(); p++) { + const Package& pkg = wspc.GetPackage(p); + String pn = wspc[p]; + for(int f = -1; f < pkg.file.GetCount(); f++) + if(f < 0 || !pkg.file[f].separator) { + Vector pkgfiles; + String pk = (f >= 0 ? SourcePath(pn, pkg.file[f]) : PackagePath(pn)); + if(!FindFile(pk).IsFile()) + continue; + pkgfiles.Add(f >= 0 ? SourcePath(pn, pkg.file[f]) : PackagePath(pn)); + pkgfiles.AppendPick(HdependGetDependencies(pkgfiles[0])); + for(int d = 0; d < pkgfiles.GetCount(); d++) { + TransferFileInfo newinfo; + newinfo.sourcepath = pkgfiles[d]; + String rp = host.GetHostPath(newinfo.sourcepath); + if(info.Find(rp) >= 0 || (d && UnixPath(rp) == UnixPath(newinfo.sourcepath))) + continue; + FindFile ff(newinfo.sourcepath); + newinfo.filetime = (int)(Time(ff.GetLastWriteTime()) - RemoteHost::TimeBase()); + newinfo.filesize = (int)ff.GetLength(); + int pos = transferfilecache.Find(rp); + if(pos < 0 || transferfilecache[pos].filetime != newinfo.filetime + || transferfilecache[pos].filesize != newinfo.filesize) + { + String content = NoCr(LoadFile(newinfo.sourcepath)); + query << rp << '\t' << newinfo.filetime << '\t' << content.GetLength() << '\n'; + // remotepath.Add(rp); + fdata.Add(content); + info.Add(rp, newinfo); + nocrsize.Add(content.GetLength()); + PutVerbose("Checking remote " + rp); + /* + if(msecs(ticks) >= 0) + { + ShowConsole(); + console.Sync(); + ticks = msecs(-200); + } + */ } + } + } + } + if(info.IsEmpty()) + return true; +// String host = GetVar("REMOTE_HOST"); +// int port = 2346; +// int ppos = host.Find(':'); +// if(ppos >= 0) +// { +// port = ScanInt(host.GetIter(ppos + 1)); +// host.Trim(ppos); +// } + + Index ignore; + { + PutConsole(NFormat("Retrieving update list for remote filesystem %s", host.host)); + ConsoleShow(); + String out = host.RemoteExec(query); + if(out[0] != 'O' || out[1] != 'K') { + PutConsole(out); + return false; + } + + const char *s = out; + while(*s && *s++ != '\n') + ; + while(*s) + { + const char *b = s; + while(*s && *s != '\n') + s++; + ignore.FindAdd(NormalizePath(NativePath(String(b, s)))); + if(*s) + s++; + } + if(ignore.GetCount() == info.GetCount()) + PutConsole("Remote source tree is up to date."); + else + { + PutConsole(NFormat("%d file(s) missing in remote source tree:", info.GetCount() - ignore.GetCount())); + for(p = 0; p < info.GetCount(); p++) + { +// console << " " << remotepath[p] << " - " +// << FormatInt(p) << " @ " << FormatInt(ignore.Find(remotepath[p])) << "\n"; + if(ignore.Find(NormalizePath(NativePath(info.GetKey(p)))) < 0) + PutConsole(String().Cat() << " " << info.GetKey(p)); + } + } + } + + Vector update; + for(p = 0; p < info.GetCount(); p++) + if(ignore.Find(NormalizePath(NativePath(info.GetKey(p)))) < 0) + { + String rawdata = fdata[p]; + PutConsole(String().Cat() << "Compressing " << info[p].sourcepath << " (" << FormatInt(rawdata.GetLength()) << " B)\n"); + ConsoleSync(); + String bzdata = BZ2Compress(rawdata); + String comp = ASCII85Encode(bzdata); + if(update.IsEmpty() || update.Top().GetLength() + comp.GetLength() >= 500000) + update.Add(">"); + update.Top() << info.GetKey(p) << '\t' << info[p].filetime << '\t' << nocrsize[p] << '\t' << comp << '\n'; + } + + for(p = 0; p < update.GetCount(); p++) + { + PutConsole(NFormat("Uploading block %d / %d (%d B)", p + 1, update.GetCount(), update[p].GetLength())); + ConsoleShow(); + String result = host.RemoteExec(update[p]); + if(result[0] != 'O' || result[1] != 'K') { + PutConsole(result); + return false; + } + } + + for(p = 0; p < info.GetCount(); p++) + transferfilecache.GetAdd(info.GetKey(p)) = info[p]; + return true; +} +#endif + +One MakeBuild::CreateHost(bool sync_files) +{ + SetupDefaultMethod(); + VectorMap bm = GetMethodVars(method); + One outhost; +#if 0 // REMOTE REMOVED + String rm = bm.Get("REMOTE_HOST", Null); + if(!IsNull(rm)) { + One host = new RemoteHost; + host->host = rm; + host->port = 2346; + int f = rm.Find(':'); + if(f >= 0) { + host->host = rm.Left(f); + host->port = Nvl(ScanInt(rm.GetIter(f + 1)), host->port); + } + host->os_type = bm.Get("REMOTE_OS", "UNIX"); + Vector path_map = Split(bm.Get("REMOTE_MAP", Null), ';'); + for(int p = 0; p < path_map.GetCount(); p++) { + f = path_map[p].Find('>'); + if(f >= 0) { + host->path_map_local.Add(path_map[p].Left(f)); + host->path_map_remote.Add(path_map[p].Mid(f + 1)); + } + } + VectorMap env(Environment(), 1); + Vector exedirs = SplitDirs(bm.Get("PATH", "") + ';' + env.Get("PATH", "")); + env.GetAdd("PATH") = Join(exedirs, ";"); + for(int i = 0; i < env.GetCount(); i++) + host->environment << env.GetKey(i) << '=' << env[i] << '\0'; + host->environment.Cat(0); + if(sync_files && bm.Get("REMOTE_TRANSFER", Null) != "0") + SyncHostFiles(*host); + outhost = -host; + } + else +#endif + { + One host = new LocalHost; + VectorMap env(Environment(), 1); + host->exedirs = SplitDirs(bm.Get("PATH", "") + ';' + env.Get("PATH", "")); + env.GetAdd("PATH") = Join(host->exedirs, ";"); + env.GetAdd("UPP_MAIN__") = GetFileDirectory(PackagePath(GetMain())); + env.GetAdd("UPP_ASSEMBLY__") = GetVar("UPP"); + for(int i = 0; i < env.GetCount(); i++) { + LDUMP(env.GetKey(i)); + LDUMP(env[i]); + host->environment << env.GetKey(i) << '=' << env[i] << '\0'; + } + host->environment.Cat(0); + host->cmdout = &cmdout; + outhost = -host; + } + return outhost; +} + +One MakeBuild::CreateBuilder(Host *host) +{ + SetupDefaultMethod(); + VectorMap bm = GetMethodVars(method); + String builder = bm.Get("BUILDER", "GCC"); + int q = BuilderMap().Find(builder); + if(q < 0) { + PutConsole("Invalid builder " + builder); + ConsoleShow(); + return NULL; + } + One b = (*BuilderMap().Get(builder))(); + b->host = host; + b->compiler = bm.Get("COMPILER", ""); + b->include = SplitDirs(GetVar("UPP") + ';' + bm.Get("INCLUDE", "")); + const Workspace& wspc = GetIdeWorkspace(); + for(int i = 0; i < wspc.GetCount(); i++) { + const Package& pkg = wspc.GetPackage(i); + for(int j = 0; j < pkg.include.GetCount(); j++) + b->include.Add(SourcePath(wspc[i], pkg.include[j].text)); + } + b->libpath = SplitDirs(bm.Get("LIB", "")); + b->debug_options = bm.Get("DEBUG_OPTIONS", ""); + b->release_options = bm.Get("RELEASE_OPTIONS", ""); + b->release_size_options = bm.Get("RELEASE_SIZE_OPTIONS", ""); + b->debug_link = bm.Get("DEBUG_LINK", ""); + b->release_link = bm.Get("RELEASE_LINK", ""); + b->script = bm.Get("SCRIPT", ""); + return b; +} + +int CharFilterSlash(int c) +{ + return c == '\\' ? '/' : c; +} + +bool output_per_assembly; + +String MakeBuild::OutDir(const Index& cfg, const String& package, const VectorMap& bm, + bool use_target) +{ + Index excl; + excl.Add(bm.Get("BUILDER", "GCC")); + excl.Add("MSC"); + LocalHost().AddFlags(excl); + Vector x; + bool dbg = cfg.Find("DEBUG_FULL") >= 0 || cfg.Find("DEBUG_MINIMAL") >= 0; + if(cfg.Find("DEBUG") >= 0) { + excl.Add("BLITZ"); + if(cfg.Find("BLITZ") < 0) + x.Add("NOBLITZ"); + } + else + if(dbg) + x.Add("RELEASE"); + if(use_target) + excl.Add("MAIN"); + for(int i = 0; i < cfg.GetCount(); i++) + if(excl.Find(cfg[i]) < 0) + x.Add(cfg[i]); + Sort(x); + for(int i = 0; i < x.GetCount(); i++) + x[i] = InitCaps(x[i]); + String outdir = GetVar("OUTPUT"); + if(output_per_assembly) + outdir = AppendFileName(outdir, GetVarsName()); + if(!use_target) + outdir = AppendFileName(outdir, package); + outdir = AppendFileName(outdir, GetFileTitle(method) + "." + Join(x, ".")); + outdir = Filter(outdir, CharFilterSlash); + return outdir; +} + +struct OneFileHost : Host { + One host; + String onefile; + + virtual String GetEnvironment() { return host->GetEnvironment(); } + virtual String GetHostPath(const String& path) { return host->GetHostPath(path); } + virtual String GetLocalPath(const String& path) { return host->GetLocalPath(path); } + virtual String NormalizePath(const String& path) { return host->NormalizePath(path); } + virtual void DeleteFile(const Vector& path) { host->DeleteFile(path); } + virtual void DeleteFolderDeep(const String& folder) { host->DeleteFolderDeep(folder); } + virtual void ChDir(const String& path) { host->ChDir(path); } + virtual void RealizeDir(const String& path) { host->RealizeDir(path); } + virtual void SaveFile(const String& path, const String& data) { host->SaveFile(path, data); } + virtual String LoadFile(const String& path) { return host->LoadFile(path); } + virtual int Execute(const char *c) { return host->Execute(c); } + virtual int ExecuteWithInput(const char *c) { return host->ExecuteWithInput(c); } + virtual int Execute(const char *c, Stream& o) { return host->Execute(c, o); } + virtual int AllocSlot() { return host->AllocSlot(); } + virtual bool Run(const char *cmdline, int slot, String key, int blitz_count) { return host->Run(cmdline, slot, key, blitz_count); } + virtual bool Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) { return host->Run(cmdline, out, slot, key, blitz_count); } + virtual bool Wait() { return host->Wait(); } + virtual One StartProcess(const char *c) { return host->StartProcess(c); } + virtual void Launch(const char *cmdline, bool) { host->Launch(cmdline); } + virtual void AddFlags(Index& cfg) { host->AddFlags(cfg); } + + virtual Vector GetFileInfo(const Vector& path) { + Vector fi = host->GetFileInfo(path); + for(int i = 0; i < path.GetCount(); i++) + if(path[i] == onefile) + (Time &)fi[i] = GetSysTime(); + else + (Time &)fi[i] = Time::Low(); + return fi; + } +}; + +bool MakeBuild::BuildPackage(const Workspace& wspc, int pkindex, int pknumber, int pkcount, + String mainparam, String outfile, Vector& linkfile, String& linkopt, bool link) +{ + String package = wspc[pkindex]; + String mainpackage = wspc[0]; + const Package& pkg = wspc.package[pkindex]; + VectorMap bm = GetMethodVars(method); + if(bm.GetCount() == 0) { + PutConsole("Invalid build method"); + ConsoleShow(); + return false; + } + One host = CreateHost(false); + if(!IsNull(onefile)) { + OneFileHost *h = new OneFileHost; + h->host = host; + h->onefile = onefile; + host = h; + } + One b = CreateBuilder(~host); + if(!b) + return false; + b->config = PackageConfig(wspc, pkindex, bm, mainparam, *host, *b); + const TargetMode& m = targetmode == 0 ? debug : release; + b->version = m.version; + b->method = method; + b->outdir = OutDir(b->config, package, bm); + host->RealizeDir(b->outdir); + String mainfn = Null; + Index mcfg = PackageConfig(wspc, 0, bm, mainparam, *host, *b, &mainfn); + HdependClearDependencies(); + for(int i = 0; i < pkg.GetCount(); i++) { + const Array& f = pkg[i].depends; + for(int j = 0; j < f.GetCount(); j++) + if(MatchWhen(f[j].when, mcfg.GetKeys())) + HdependAddDependency(SourcePath(package, pkg[i]), SourcePath(package, f[j].text)); + } + String tout = OutDir(mcfg, mainpackage, bm, use_target); + host->RealizeDir(tout); + if(IsNull(mainfn)) + mainfn = GetFileTitle(mainpackage) + b->GetTargetExt(); + if(!IsNull(outfile)) + target = NormalizePath(outfile, tout); + else { + if(m.target_override && !IsNull(m.target) && IsFolder(m.target)) + target = host->NormalizePath(AppendFileName(m.target, mainfn)); + else + if(m.target_override && (IsFullPath(m.target) || *m.target == '/' || *m.target == '\\')) + target = m.target; + else + if(m.target_override && !IsNull(m.target)) + target = host->NormalizePath(AppendFileName(tout, m.target)); + else + if(IsFullPath(mainfn)) + target = mainfn; + else + target = host->NormalizePath(AppendFileName(tout, mainfn)); + } + b->target = target; + b->mainpackage = mainpackage; + if(IsNull(onefile)) { + String out; + out << "----- " << package << " ( " << Join(b->config.GetKeys(), " ") << " )"; + if(pkcount > 1) + out << " (" << (pknumber + 1) << " / " << pkcount << ')'; + PutConsole(out); + } + else + b->config.FindAdd("NOLIB"); + bool ok = b->BuildPackage(package, linkfile, linkopt, + GetAllUses(wspc, pkindex), + GetAllLibraries(wspc, pkindex, bm, mainparam, *host, *b), + targetmode - 1); + Vector errors = PickErrors(); + host->DeleteFile(errors); + if(!ok || !errors.IsEmpty()) + return false; + if(link) { + ok = b->Link(linkfile, linkopt, GetTargetMode().createmap); + errors = PickErrors(); + host->DeleteFile(errors); + if(!ok || !errors.IsEmpty()) + return false; + } + return true; +} + +void MakeBuild::SetHdependDirs() +{ + Vector include = SplitDirs(GetVar("UPP") + ';' + + GetMethodVars(method).Get("INCLUDE", "") + ';' + + Environment().Get("INCLUDE", "") +#ifdef PLATFORM_POSIX + + ";/usr/include;/usr/local/include" +#endif + ); + // Also adding internal includes + const Workspace& wspc = GetIdeWorkspace(); + for(int i = 0; i < wspc.GetCount(); i++) { + const Package& pkg = wspc.GetPackage(i); + for(int j = 0; j < pkg.include.GetCount(); j++) + include.Add(SourcePath(wspc[i], pkg.include[j].text)); + } + + HdependSetDirs(include); +} + +Vector MakeBuild::GetAllUses(const Workspace& wspc, int f) +{ // Warning: This does not seem to do what it is supposed to do... + String package = wspc[f]; + Index all_uses; + bool warn = true; + int n = 0; + while(f >= 0) { + const Package& p = wspc.package[f]; + for(int fu = 0; fu < p.uses.GetCount(); fu++) + if(p.uses[fu].text != package) + all_uses.FindAdd(p.uses[fu].text); + else if(warn) { + PutConsole(NFormat("%s: circular 'uses' chain", package)); + warn = false; + } + f = -1; + while(n < all_uses.GetCount() && (f = wspc.package.Find(all_uses[n++])) < 0) + ; + } + return all_uses.PickKeys(); +} + +Vector MakeBuild::GetAllLibraries(const Workspace& wspc, int index, + const VectorMap& bm, String mainparam, + Host& host, Builder& builder) +{ // Warning: This does not seem to do what it is supposed to do... + Vector uses = GetAllUses(wspc, index); + uses.Add(wspc[index]); + Index libraries; + + for(int i = 0; i < uses.GetCount(); i++) { + int f = wspc.package.Find(UnixPath(uses[i])); + if(f >= 0) { + const Package& pk = wspc.package[f]; + Index config = PackageConfig(wspc, f, bm, mainparam, host, builder); + Vector pklibs = Split(Gather(pk.library, config.GetKeys()), ' '); + FindAppend(libraries, pklibs); + } + } + return libraries.PickKeys(); +} + +bool MakeBuild::Build(const Workspace& wspc, String mainparam, String outfile, bool clear_console) +{ + ClearErrorEditor(); + BeginBuilding(true, clear_console); + bool ok = true; + if(wspc.GetCount()) { + Vector build_order; + if(GetTargetMode().linkmode != 2) { + for(int i = 1; i < wspc.GetCount(); i++) + build_order.Add(i); + } + else { + Index remaining; + for(int i = 1; i < wspc.GetCount(); i++) + remaining.Add(i); + while(!remaining.IsEmpty()) { + int t; + for(t = 0; t < remaining.GetCount(); t++) { + const Package& pk = wspc.package[remaining[t]]; + bool delay = false; + for(int u = 0; u < pk.uses.GetCount(); u++) + if(remaining.Find(wspc.package.Find(pk.uses[u].text)) >= 0) { + delay = true; + break; + } + if(!delay) + break; + } + if(t >= remaining.GetCount()) + t = 0; + build_order.Add(remaining[t]); + remaining.Remove(t); + } + } + String mainpackage = wspc[0]; + Vector linkfile; + String linkopt = GetMethodVars(method).Get(targetmode ? "RELEASE_LINK" : "DEBUG_LINK", Null); + if(linkopt.GetCount()) + linkopt << ' '; + ok = true; + int ms = msecs(); + for(int i = 0; i < build_order.GetCount() && (ok || !stoponerrors); i++) { + int px = build_order[i]; + ok = BuildPackage(wspc, px, i, build_order.GetCount() + 1, + mainparam, Null, linkfile, linkopt) && ok; + if(msecs() - ms >= 200) { + DoProcessEvents(); + ms = msecs(); + } + } + if(ok || !stoponerrors) + ok = BuildPackage(wspc, 0, build_order.GetCount(), build_order.GetCount() + 1, + mainparam, outfile, linkfile, linkopt, ok) && ok; + } + EndBuilding(ok); + ReQualifyCodeBase(); + SetErrorEditor(); + return ok; +} + +bool MakeBuild::Build() +{ + VectorMap bm = GetMethodVars(method); + if(bm.GetCount() == 0) { + PutConsole("Invalid build method"); + ConsoleShow(); + return false; + } + One host = CreateHost(false); + One builder = CreateBuilder(~host); + if(!builder) + return false; + Index p = PackageConfig(GetIdeWorkspace(), 0, bm, mainconfigparam, + *host, *builder); + Workspace wspc; + wspc.Scan(GetMain(), p.GetKeys()); + return Build(wspc, mainconfigparam, Null); +} + +void MakeBuild::CleanPackage(const Workspace& wspc, int package) +{ + PutConsole(NFormat("Cleaning %s", wspc[package])); + One host = CreateHost(false); + One builder = CreateBuilder(~host); + if(!builder) + return; + host->DeleteFolderDeep(OutDir(PackageConfig(wspc, package, GetMethodVars(method), mainconfigparam, + *host, *builder), wspc[package], GetMethodVars(method))); +} + +void MakeBuild::Clean() +{ + ConsoleClear(); + const Workspace& wspc = GetIdeWorkspace(); + for(int i = 0; i < wspc.GetCount(); i++) + CleanPackage(wspc, i); + PutConsole("...done"); +} + +void MakeBuild::RebuildAll() +{ + Clean(); + Build(); +} + +void MakeBuild::SaveMakeFile(const String& fn, bool exporting) +{ + BeginBuilding(false, true); + + VectorMap bm = GetMethodVars(method); + One host = CreateHost(false); + One b = CreateBuilder(~host); + + if(!b) + return; + + const TargetMode& tm = GetTargetMode(); + + String makefile; + + Vector uppdirs = GetUppDirs(); + String uppout = exporting ? host->GetHostPath(GetVar("OUTPUT")) : "_out/"; + String inclist; + + Index allconfig = PackageConfig(GetIdeWorkspace(), 0, bm, mainconfigparam, *host, *b); + bool win32 = allconfig.Find("WIN32") >= 0; + + Workspace wspc; + wspc.Scan(GetMain(), allconfig.GetKeys()); + + for(int i = 1; i < wspc.GetCount(); i++) { + Index modconfig = PackageConfig(wspc, i, bm, mainconfigparam, *host, *b); + for(int a = allconfig.GetCount(); --a >= 0;) + if(modconfig.Find(allconfig[a]) < 0) + allconfig.Remove(a); + } + + if(!exporting) + for(int i = 0; i < uppdirs.GetCount(); i++) { + String srcdir = GetMakePath(AdjustMakePath(host->GetHostPath(AppendFileName(uppdirs[i], ""))), win32); + makefile << "UPPDIR" << (i + 1) << " = " << srcdir << "\n"; + inclist << " -I$(UPPDIR" << (i + 1) << ")"; + } + else + inclist << "-I./"; + Vector includes = SplitDirs(bm.Get("INCLUDE","")); + for(int i = 0; i < includes.GetCount(); i++) + inclist << " -I" << includes[i]; + + makefile << "\n" + "UPPOUT = " << (exporting ? "_out/" : GetMakePath(AdjustMakePath(host->GetHostPath(AppendFileName(uppout, ""))), win32)) << "\n" + "CINC = " << inclist << "\n" + "Macro = "; + + for(int i = 0; i < allconfig.GetCount(); i++) + makefile << " -Dflag" << allconfig[i]; + makefile << "\n"; + + String output, config, install, rules, linkdep, linkfiles, linkfileend; + + for(int i = 0; i < wspc.GetCount(); i++) { + b->config = PackageConfig(wspc, i, bm, mainconfigparam, *host, *b); + b->version = tm.version; + b->method = method; + MakeFile mf; + b->AddMakeFile(mf, wspc[i], GetAllUses(wspc, i), + GetAllLibraries(wspc, i, bm, mainconfigparam, *host, *b), allconfig, + exporting); + if(!i) { + String tdir = mf.outdir; + String trg; + if(tm.target_override) { + trg = GetMakePath(AdjustMakePath(tm.target), win32); + if(!trg.IsEmpty() && *trg.Last() == (win32 ? '\\' : '/')) + trg << mf.outfile; + else if(trg.Find(win32 ? '\\' : '/') < 0) + trg.Insert(0, "$(OutDir)"); + } + output = Nvl(trg, mf.output); + if(exporting) + output = wspc[i] + ".out"; + install << "\n" + "OutDir = " << tdir << "\n" + "OutFile = " << output << "\n" + "\n" + ".PHONY: all\n" + "all: prepare $(OutFile)\n" + "\n" + ".PHONY: prepare\n" + "prepare:\n"; + } + config << mf.config; + install << mf.install; + rules << mf.rules; + linkdep << mf.linkdep; + linkfiles << mf.linkfiles; + linkfileend << mf.linkfileend; + } + + makefile + << config + << install + << "\n" + "$(OutFile): " << linkdep << "\n\t" << linkfiles << linkfileend << " -Wl,--end-group\n\n" + << rules + << ".PHONY: clean\n" + << "clean:\n" + << "\tif [ -d $(UPPOUT) ]; then rm -rf $(UPPOUT); fi;\n"; + + bool sv = ::SaveFile(fn, makefile); + if(!exporting) + if(sv) + PutConsole(NFormat("%s(1): makefile generation complete", fn)); + else + PutConsole(NFormat("%s: error writing makefile", fn)); + + EndBuilding(true); +} diff --git a/uppsrc/ide/Builders/Build.h b/uppsrc/ide/Builders/Build.h index 9a90bfb26..c8aaf1537 100644 --- a/uppsrc/ide/Builders/Build.h +++ b/uppsrc/ide/Builders/Build.h @@ -63,7 +63,7 @@ struct MakeBuild { const TargetMode& GetTargetMode(); Index PackageConfig(const Workspace& wspc, int package, const VectorMap& bm, String mainparam, Host& host, Builder& b, String *target = NULL); - bool SyncHostFiles(RemoteHost& host); +// bool SyncHostFiles(RemoteHost& host); One CreateHost(bool sync_files); One CreateBuilder(Host *host); String OutDir(const Index& cfg, const String& package, diff --git a/uppsrc/ide/Console.cpp b/uppsrc/ide/Console.cpp index 2cad23988..5cb7a9a22 100644 --- a/uppsrc/ide/Console.cpp +++ b/uppsrc/ide/Console.cpp @@ -146,7 +146,7 @@ int Console::Flush() return !running ? -1 : done_output ? 1 : 0; } -int Console::Execute(One p, const char *command, Stream *out, bool q) +int Console::Execute(One p, const char *command, Stream *out, bool q) { Wait(); if(!Run(p, command, out, q, 0)) @@ -159,12 +159,14 @@ int Console::Execute(const char *command, Stream *out, const char *envptr, bool { try { Wait(); - return Execute(StartProcess(command, envptr, REMOTE_TIMEOUT), command, out, q); + One p; + if(p.Create().Start(command, envptr)) + return Execute(p, command, out, q); } catch(Exc e) { - ProcessEvents(); - return Null; } + ProcessEvents(); + return Null; } int Console::AllocSlot() @@ -188,17 +190,18 @@ bool Console::Run(const char *cmdline, Stream *out, const char *envptr, bool qui { try { Wait(slot); - One sproc = StartProcess(cmdline, envptr, REMOTE_TIMEOUT); - return !!sproc && Run(sproc, cmdline, out, quiet, slot, key, blitz_count); + One sproc; + return sproc.Create().Start(cmdline, envptr) && + Run(sproc, cmdline, out, quiet, slot, key, blitz_count); } catch(Exc e) { Append(e); - ProcessEvents(); - return false; } + ProcessEvents(); + return false; } -bool Console::Run(One process, const char *cmdline, Stream *out, bool quiet, int slot, String key, int blitz_count) +bool Console::Run(One process, const char *cmdline, Stream *out, bool quiet, int slot, String key, int blitz_count) { if(!process) { if(verbosebuild) @@ -300,7 +303,8 @@ void Console::Kill(int islot) { Slot& slot = processes[islot]; if(slot.process) { - slot.process->Kill(); + if(slot.process->IsRunning()) + slot.process->Kill(); slot.exitcode = slot.process->GetExitCode(); if(slot.exitcode != 0 && !IsNull(slot.key)) error_keys.Add(slot.key); diff --git a/uppsrc/ide/Core/Core.cpp b/uppsrc/ide/Core/Core.cpp index 21aa88673..4881b8bb7 100644 --- a/uppsrc/ide/Core/Core.cpp +++ b/uppsrc/ide/Core/Core.cpp @@ -146,7 +146,7 @@ int IdeConsoleExecuteWithInput(const char *cmdline, Stream *out, const char *env return the_ide ? the_ide->IdeConsoleExecuteWithInput(cmdline, out, envptr, quiet) : -1; } -int IdeConsoleExecute(One process, const char *cmdline, Stream *out, bool quiet) +int IdeConsoleExecute(One process, const char *cmdline, Stream *out, bool quiet) { return the_ide ? the_ide->IdeConsoleExecute(process, cmdline, out, quiet) : -1; } @@ -161,7 +161,7 @@ bool IdeConsoleRun(const char *cmdline, Stream *out, const char *envptr, bool qu return the_ide && the_ide->IdeConsoleRun(cmdline, out, envptr, quiet, slot, key, blitz_count); } -bool IdeConsoleRun(One process, const char *cmdline, Stream *out, bool quiet, int slot, String key, int blitz_count) +bool IdeConsoleRun(One process, const char *cmdline, Stream *out, bool quiet, int slot, String key, int blitz_count) { return the_ide && the_ide->IdeConsoleRun(process, cmdline, out, quiet, slot, key, blitz_count); } diff --git a/uppsrc/ide/Core/Core.h b/uppsrc/ide/Core/Core.h index 9289a9c5f..49a23c7c8 100644 --- a/uppsrc/ide/Core/Core.h +++ b/uppsrc/ide/Core/Core.h @@ -2,7 +2,7 @@ #define COMMON_H #include -#include +// #include #include #include @@ -45,10 +45,10 @@ public: virtual String IdeGetOneFile() const = 0; virtual int IdeConsoleExecute(const char *cmdline, Stream *out = NULL, const char *envptr = NULL, bool quiet = false) = 0; virtual int IdeConsoleExecuteWithInput(const char *cmdline, Stream *out, const char *envptr, bool quiet) = 0; - virtual int IdeConsoleExecute(One process, const char *cmdline, Stream *out = NULL, bool quiet = false) = 0; + virtual int IdeConsoleExecute(One process, const char *cmdline, Stream *out = NULL, bool quiet = false) = 0; virtual int IdeConsoleAllocSlot() = 0; virtual bool IdeConsoleRun(const char *cmdline, Stream *out = NULL, const char *envptr = NULL, bool quiet = false, int slot = 0, String key = Null, int blitz_count = 1) = 0; - virtual bool IdeConsoleRun(One process, const char *cmdline, Stream *out = NULL, bool quiet = false, int slot = 0, String key = Null, int blitz_count = 1) = 0; + virtual bool IdeConsoleRun(One process, const char *cmdline, Stream *out = NULL, bool quiet = false, int slot = 0, String key = Null, int blitz_count = 1) = 0; virtual void IdeConsoleFlush() = 0; virtual void IdeConsoleBeginGroup(String group) = 0; virtual void IdeConsoleEndGroup() = 0; @@ -95,10 +95,10 @@ bool IdeIsBuilding(); String IdeGetOneFile(); int IdeConsoleExecute(const char *cmdline, Stream *out = NULL, const char *envptr = NULL, bool quiet = false); int IdeConsoleExecuteWithInput(const char *cmdline, Stream *out, const char *envptr, bool quiet); -int IdeConsoleExecute(One process, const char *cmdline, Stream *out = NULL, bool quiet = false); +int IdeConsoleExecute(One process, const char *cmdline, Stream *out = NULL, bool quiet = false); int IdeConsoleAllocSlot(); bool IdeConsoleRun(const char *cmdline, Stream *out = NULL, const char *envptr = NULL, bool quiet = false, int slot = 0, String key = Null, int blitz_count = 1); -bool IdeConsoleRun(One process, const char *cmdline, Stream *out = NULL, bool quiet = false, int slot = 0, String key = Null, int blitz_count = 1); +bool IdeConsoleRun(One process, const char *cmdline, Stream *out = NULL, bool quiet = false, int slot = 0, String key = Null, int blitz_count = 1); void IdeConsoleFlush(); void IdeConsoleBeginGroup(String group); void IdeConsoleEndGroup(); diff --git a/uppsrc/ide/Core/Core.upp b/uppsrc/ide/Core/Core.upp index 7e9a75e01..4c393950a 100644 --- a/uppsrc/ide/Core/Core.upp +++ b/uppsrc/ide/Core/Core.upp @@ -2,7 +2,6 @@ description "TheIDE - common library\377B"; uses Esc, - Web, coff/binobj, plugin/bz2; diff --git a/uppsrc/ide/Core/Host.cpp b/uppsrc/ide/Core/Host.cpp index f6f446fa8..e4f7a9563 100644 --- a/uppsrc/ide/Core/Host.cpp +++ b/uppsrc/ide/Core/Host.cpp @@ -1,573 +1,577 @@ -#include "Core.h" - -#define LLOG(x) - -#include - -String LocalHost::GetEnvironment() -{ - return environment; -} - -String LocalHost::GetHostPath(const String& path) -{ - return path; -} - -String LocalHost::GetLocalPath(const String& path) -{ - return path; -} - -String LocalHost::NormalizePath(const String& path) -{ - return ::NormalizePath(path); -} - -Vector LocalHost::GetFileInfo(const Vector& path) -{ - Vector fi; - for(int i = 0; i < path.GetCount(); i++) { - FindFile ff(path[i]); - FileInfo& f = fi.Add(); - if(ff) { - (Time&)f = ff.GetLastWriteTime(); -#ifdef PLATFORM_WIN32 - f.second = f.second & ~1; // FAT vs NTFS accuracy fix -#endif - f.length = ff.IsFile() ? (int)ff.GetLength() : -1; - } - else { - (Time&)f = Time::Low(); - f.length = Null; - } - } - return fi; -} - -void LocalHost::DeleteFile(const Vector& path) -{ - for(int i = 0; i < path.GetCount(); i++) - ::DeleteFile(path[i]); -} - -void LocalHost::DeleteFolderDeep(const String& folder) -{ - ::DeleteFolderDeep(folder); -} - -void LocalHost::ChDir(const String& path) -{ -#ifdef PLATFORM_WIN32 - SetCurrentDirectory(path); -#endif -#ifdef PLATFORM_POSIX - IGNORE_RESULT( chdir(path) ); -#endif - if(cmdout) - *cmdout << "cd \"" << GetHostPath(path) << "\"\n"; -} - -void LocalHost::DoDir(const String& dir) -{ - if(dir.GetLength() > 3) { - DoDir(GetFileFolder(dir)); - *cmdout << "mkdir \"" << dir << "\"\n"; - } -} - -void LocalHost::RealizeDir(const String& path) -{ - RealizeDirectory(path); - if(cmdout) - DoDir(path); -} - -void LocalHost::SaveFile(const String& path, const String& data) -{ - ::SaveFile(path, data); -} - -String LocalHost::LoadFile(const String& path) -{ - return ::LoadFile(path); -} - -int LocalHost::Execute(const char *cmdline) -{ - if(cmdout) - *cmdout << cmdline << '\n'; - PutVerbose(cmdline); - int q = IdeConsoleExecute(FindCommand(exedirs, cmdline), NULL, environment, false); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int LocalHost::ExecuteWithInput(const char *cmdline) -{ - if(cmdout) - *cmdout << cmdline << '\n'; - PutVerbose(cmdline); - int q = IdeConsoleExecuteWithInput(FindCommand(exedirs, cmdline), NULL, environment, false); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int LocalHost::Execute(const char *cmdline, Stream& out) -{ - PutVerbose(cmdline); - int q = IdeConsoleExecute(FindCommand(exedirs, cmdline), &out, environment, true); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int LocalHost::AllocSlot() -{ - return IdeConsoleAllocSlot(); -} - -bool LocalHost::Run(const char *cmdline, int slot, String key, int blitz_count) -{ - return IdeConsoleRun(FindCommand(exedirs, cmdline), NULL, environment, false, slot, key, blitz_count); -} - -bool LocalHost::Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) -{ - return IdeConsoleRun(FindCommand(exedirs, cmdline), &out, environment, true, slot, key, blitz_count); -} - -bool LocalHost::Wait() -{ - return IdeConsoleWait(); -} - -One LocalHost::StartProcess(const char *cmdline) -{ - try { - PutVerbose(cmdline); - return ::StartProcess(FindCommand(exedirs, cmdline), environment, REMOTE_TIMEOUT); - } - catch(...) { - return NULL; - } -} - -#ifdef PLATFORM_POSIX -//#BLITZ_APPROVE -#include -#include -#include - -static Vector& sPid() -{ - static Vector q; - return q; -} - -void sCleanZombies(int signal_number) -{ - Vector& pid = sPid(); - int i = 0; - while(i < pid.GetCount()) - if(pid[i] && waitpid(pid[i], 0, WNOHANG | WUNTRACED) > 0) - pid.Remove(i); - else - i++; -} -#endif - -String LinuxHostConsole = "/usr/bin/xterm -e"; - -void LocalHost::Launch(const char *_cmdline, bool console) -{ - String cmdline = FindCommand(exedirs, _cmdline); - PutVerbose(cmdline); -#ifdef PLATFORM_WIN32 - if(console) - cmdline = GetExeFilePath() + " ! " + cmdline; - int n = cmdline.GetLength() + 1; - Buffer cmd(n); - memcpy(cmd, cmdline, n); - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; - PROCESS_INFORMATION pi; - STARTUPINFO si; - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - String ev = ToSystemCharset(environment); - Buffer env(ev.GetCount() + 1); - memcpy(env, ev, ev.GetCount() + 1); - if(CreateProcess(NULL, cmd, &sa, &sa, TRUE, - NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE, - ~env, NULL, &si, &pi)) { - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - else - PutConsole("Unable to launch " + String(_cmdline)); -#endif -#ifdef PLATFORM_POSIX - String script = ConfigFile("console-script-" + AsString(getpid()) + ".tmp"); - int c = LinuxHostConsole.FindFirstOf(" "); - String lc = c < 0 ? LinuxHostConsole : LinuxHostConsole.Left(c); - if(FileExists(lc)) { - - if(console) { - FileStream out(script, FileStream::CREATE, 0777); - out << "#!/bin/sh\n" - << cmdline << '\n' - << "echo \"<--- Finished, press any key to close the window --->\"\nread dummy\n"; - cmdline = LinuxHostConsole + " sh " + script; - } - } - else - if(LinuxHostConsole.GetCount()) - PutConsole("Warning: Terminal '" + lc + "' not found, executing in background."); - Buffer cmd_buf(strlen(cmdline) + 1); - char *cmd_out = cmd_buf; - Vector args; - const char *p = cmdline; - const char *b = p; - while(*p && (byte)*p > ' ') - if(*p++ == '\"') - while(*p && *p++ != '\"') - ; - args.Add(cmd_out); - memcpy(cmd_out, b, p - b); - cmd_out += p - b; - *cmd_out++ = '\0'; - - while(*p) - if((byte)*p <= ' ') - p++; - else { - args.Add(cmd_out); - b = p; - while(*p && (byte)*p > ' ') - if(*p++ == '\"') - { - memcpy(cmd_out, b, p - b - 1); - cmd_out += p - b - 1; - b = p; - while(*p && *p != '\"') - p++; - memcpy(cmd_out, b, p - b); - cmd_out += p - b; - if(*p == '\"') - p++; - b = p; - } - memcpy(cmd_out, b, p - b); - cmd_out += p - b; - *cmd_out++ = '\0'; - } - - args.Add(NULL); - - ONCELOCK { - struct sigaction sigchld_action; - memset(&sigchld_action, 0, sizeof(sigchld_action)); - sigchld_action.sa_handler = sCleanZombies; - sigaction(SIGCHLD, &sigchld_action, NULL); - } - - pid_t pid = fork(); - if(pid == 0) - { - const char *from = environment; - Vector env; - while(*from) { - env.Add(from); - from += strlen(from) + 1; - } - env.Add(NULL); - const char **envp = env.Begin(); - execve(args[0], args, (char *const *)envp); - abort(); - } - LLOG("Launch pid: " << pid); - sPid().Add(pid); -#endif -} - -void LocalHost::AddFlags(Index& cfg) -{ -#if defined(PLATFORM_WIN32) - cfg.Add("WIN32"); -#endif - -#ifdef PLATFORM_LINUX - cfg.Add("LINUX"); -#endif - -#ifdef PLATFORM_POSIX - cfg.Add("POSIX"); -#endif - -#ifdef PLATFORM_BSD - cfg.Add("BSD"); -#endif - -#ifdef PLATFORM_FREEBSD - cfg.Add("FREEBSD"); -#endif - -#ifdef PLATFORM_OPENBSD - cfg.Add("OPENBSD"); -#endif - -#ifdef PLATFORM_NETBSD - cfg.Add("NETBSD"); -#endif - -#ifdef PLATFORM_SOLARIS - cfg.Add("SOLARIS"); -#endif - -#ifdef PLATFORM_OSX11 - cfg.Add("OSX11"); -#endif -} - -static bool IsSamePath(const char *a, const char *b, int count) { - for(; --count >= 0; a++, b++) - if(a != b && ToLower(*a) != ToLower(*b) && !((*a == '\\' || *a == '/') && (*b == '\\' || *b == '/'))) - return false; - return true; -} - -String RemoteHost::GetEnvironment() -{ - return environment; -} - -String RemoteHost::GetHostPath(const String& path) -{ - bool slash = (os_type != "WINDOWS"); - for(int i = 0; i < path_map_local.GetCount(); i++) { - String lc = path_map_local[i]; - if(path.GetLength() >= lc.GetLength() && IsSamePath(path, lc, lc.GetLength())) - { - String r = CatAnyPath(path_map_remote[i], path.Mid(lc.GetLength())); - return slash ? UnixPath(r) : WinPath(r); - } - } - return slash ? UnixPath(path) : WinPath(path); -} - -String RemoteHost::GetLocalPath(const String& path) -{ - for(int i = 0; i < path_map_remote.GetCount(); i++) { - String rc = path_map_remote[i]; - if(path.GetLength() >= rc.GetLength() && IsSamePath(path, rc, rc.GetLength())) - return path_map_local[i] + path.Mid(rc.GetLength()); - } - if(!memcmp(path, "/cygdrive/", 10)) - { - const char *s = path.Begin() + 10; - String out; - if(*s) - out << *s++ << ':'; - out << s; - return out; - } - return NativePath(path); -} - -String RemoteHost::NormalizePath(const String& path) -{ - return path; -} - -String RemoteHost::RemoteExec(String cmd) -{ - Socket socket; - String sockerr; -/* - String hostname = host; - int port = 2346; - int ppos = hostname.Find(':'); - if(ppos >= 0) - { - port = atoi(host.GetIter(ppos + 1)); - hostname.Trim(ppos); - } -*/ - if(!ClientSocket(socket, host, port, true, NULL, 2000)) { - PutConsole(NFormat("Error connecting to '%s', port %d: %s", host, port, Socket::GetErrorText())); - return String::GetVoid(); - } - socket.Write(cmd); - socket.Write("\0", 1); - return socket.ReadUntil('\0', Null, 10000000); -} - -Vector RemoteHost::GetFileInfo(const Vector& path) -{ - VectorMap out; - out.Reserve(path.GetCount()); - String request; - request << "@" << (int)(GetSysTime() - TimeBase()) << ":"; - for(int i = 0; i < path.GetCount(); i++) - { - String hp = GetHostPath(path[i]); - request << hp << "\n"; - FileInfo& fi = out.Add(hp); - (Time&)fi = Time::Low(); - fi.length = Null; - } - String result = RemoteExec(request); - const char *p = result; - while(*p) - { - const char *b = p; - while(*p && *p != '\n' && *p != '\t') - p++; - String fn(b, p); - Time time = Time::Low(); - int size = Null; - if(*p == '\t') - { - int t = ScanInt(p + 1, &p); - if(!IsNull(t)) - time = TimeBase() + t; - if(*p == '\t') - size = ScanInt(p + 1, &p); - } - int ifn = out.Find(fn); - if(ifn >= 0) - { - (Time&)out[ifn] = time; - out[ifn].length = size; - } - while(*p && *p++ != '\n') - ; - } - return out.PickValues(); -} - -void RemoteHost::DeleteFile(const Vector& path) -{ - String request = "-"; - for(int i = 0; i < path.GetCount(); i++) - request << GetHostPath(path[i]) << "\n"; - String out = RemoteExec(request); - if(!IsNull(out) && out != "OK") - PutVerbose(out); -} - -void RemoteHost::DeleteFolderDeep(const String& folder) -{ - String out = RemoteExec("~" + GetHostPath(folder)); - if(out != "OK") - PutConsole(out); -} - -void RemoteHost::ChDir(const String& path) -{ - chdir_path = GetHostPath(path); -} - -void RemoteHost::RealizeDir(const String& path) -{ - RemoteExec("*" + GetHostPath(path)); -} - -void RemoteHost::SaveFile(const String& path, const String& data) -{ - String request; - request << ">" << GetHostPath(path) - << "\t" << int(GetSysTime() - TimeBase()) - << "\t" << data.GetLength() - << "\t" << ASCII85Encode(BZ2Compress(data)) - << "\n"; - String out = RemoteExec(request); - if(out != "OK") - PutConsole(out); -} - -String RemoteHost::LoadFile(const String& path) -{ - String hpath = GetHostPath(path); - String request = "^" + hpath; - String out = RemoteExec(request); - const char *p = out; - while(*p && *p != '\n' && *p != '\t') - p++; - if(*p++ != '\t') - return String::GetVoid(); - int len = ScanInt(p, &p); - if(IsNull(len) || len <= 0 || *p++ != '\t') - return String::GetVoid(); - String data = BZ2Decompress(ASCII85Decode(p)); - if(data.GetLength() != len) - { - PutConsole(NFormat("%s: decompressed length (%d) doesn't match length in header (%d)", - hpath, data.GetLength(), len)); - return String::GetVoid(); - } - return data; -} - -int RemoteHost::Execute(const char *cmdline) -{ - int q = IdeConsoleExecute(StartProcess(cmdline), cmdline); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int RemoteHost::ExecuteWithInput(const char *cmdline) -{ - int q = IdeConsoleExecute(StartProcess(cmdline), cmdline); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int RemoteHost::Execute(const char *cmdline, Stream& out) -{ - int q = IdeConsoleExecute(StartProcess(cmdline), cmdline, &out, true); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int RemoteHost::AllocSlot() -{ - return IdeConsoleAllocSlot(); -} - -bool RemoteHost::Run(const char *cmdline, int slot, String key, int blitz_count) -{ - return IdeConsoleRun(StartProcess(cmdline), cmdline, NULL, false, slot, key, blitz_count); -} - -bool RemoteHost::Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) -{ - return IdeConsoleRun(StartProcess(cmdline), cmdline, &out, false, slot, key, blitz_count); -} - -bool RemoteHost::Wait() -{ - return IdeConsoleWait(); -} - -One RemoteHost::StartProcess(const char *cmdline) -{ - try { - PutVerbose(cmdline); - return StartRemoteProcess(host, port, cmdline, environment, REMOTE_TIMEOUT); - } - catch(...) { - return NULL; - } -} - -void RemoteHost::Launch(const char *_cmdline, bool) -{ -} - -void RemoteHost::AddFlags(Index& cfg) -{ - cfg.Add(os_type); -} +#include "Core.h" + +#define LLOG(x) + +#include + +String LocalHost::GetEnvironment() +{ + return environment; +} + +String LocalHost::GetHostPath(const String& path) +{ + return path; +} + +String LocalHost::GetLocalPath(const String& path) +{ + return path; +} + +String LocalHost::NormalizePath(const String& path) +{ + return ::NormalizePath(path); +} + +Vector LocalHost::GetFileInfo(const Vector& path) +{ + Vector fi; + for(int i = 0; i < path.GetCount(); i++) { + FindFile ff(path[i]); + FileInfo& f = fi.Add(); + if(ff) { + (Time&)f = ff.GetLastWriteTime(); +#ifdef PLATFORM_WIN32 + f.second = f.second & ~1; // FAT vs NTFS accuracy fix +#endif + f.length = ff.IsFile() ? (int)ff.GetLength() : -1; + } + else { + (Time&)f = Time::Low(); + f.length = Null; + } + } + return fi; +} + +void LocalHost::DeleteFile(const Vector& path) +{ + for(int i = 0; i < path.GetCount(); i++) + ::DeleteFile(path[i]); +} + +void LocalHost::DeleteFolderDeep(const String& folder) +{ + ::DeleteFolderDeep(folder); +} + +void LocalHost::ChDir(const String& path) +{ +#ifdef PLATFORM_WIN32 + SetCurrentDirectory(path); +#endif +#ifdef PLATFORM_POSIX + IGNORE_RESULT( chdir(path) ); +#endif + if(cmdout) + *cmdout << "cd \"" << GetHostPath(path) << "\"\n"; +} + +void LocalHost::DoDir(const String& dir) +{ + if(dir.GetLength() > 3) { + DoDir(GetFileFolder(dir)); + *cmdout << "mkdir \"" << dir << "\"\n"; + } +} + +void LocalHost::RealizeDir(const String& path) +{ + RealizeDirectory(path); + if(cmdout) + DoDir(path); +} + +void LocalHost::SaveFile(const String& path, const String& data) +{ + ::SaveFile(path, data); +} + +String LocalHost::LoadFile(const String& path) +{ + return ::LoadFile(path); +} + +int LocalHost::Execute(const char *cmdline) +{ + if(cmdout) + *cmdout << cmdline << '\n'; + PutVerbose(cmdline); + int q = IdeConsoleExecute(FindCommand(exedirs, cmdline), NULL, environment, false); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int LocalHost::ExecuteWithInput(const char *cmdline) +{ + if(cmdout) + *cmdout << cmdline << '\n'; + PutVerbose(cmdline); + int q = IdeConsoleExecuteWithInput(FindCommand(exedirs, cmdline), NULL, environment, false); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int LocalHost::Execute(const char *cmdline, Stream& out) +{ + PutVerbose(cmdline); + int q = IdeConsoleExecute(FindCommand(exedirs, cmdline), &out, environment, true); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int LocalHost::AllocSlot() +{ + return IdeConsoleAllocSlot(); +} + +bool LocalHost::Run(const char *cmdline, int slot, String key, int blitz_count) +{ + return IdeConsoleRun(FindCommand(exedirs, cmdline), NULL, environment, false, slot, key, blitz_count); +} + +bool LocalHost::Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) +{ + return IdeConsoleRun(FindCommand(exedirs, cmdline), &out, environment, true, slot, key, blitz_count); +} + +bool LocalHost::Wait() +{ + return IdeConsoleWait(); +} + +One LocalHost::StartProcess(const char *cmdline) +{ + try { + PutVerbose(cmdline); + One p; + if(p.Create().Start(FindCommand(exedirs, cmdline), environment)) + return p; + } + catch(...) { + } + return NULL; +} + +#ifdef PLATFORM_POSIX +//#BLITZ_APPROVE +#include +#include +#include + +static Vector& sPid() +{ + static Vector q; + return q; +} + +void sCleanZombies(int signal_number) +{ + Vector& pid = sPid(); + int i = 0; + while(i < pid.GetCount()) + if(pid[i] && waitpid(pid[i], 0, WNOHANG | WUNTRACED) > 0) + pid.Remove(i); + else + i++; +} +#endif + +String LinuxHostConsole = "/usr/bin/xterm -e"; + +void LocalHost::Launch(const char *_cmdline, bool console) +{ + String cmdline = FindCommand(exedirs, _cmdline); + PutVerbose(cmdline); +#ifdef PLATFORM_WIN32 + if(console) + cmdline = GetExeFilePath() + " ! " + cmdline; + int n = cmdline.GetLength() + 1; + Buffer cmd(n); + memcpy(cmd, cmdline, n); + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + PROCESS_INFORMATION pi; + STARTUPINFO si; + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + String ev = ToSystemCharset(environment); + Buffer env(ev.GetCount() + 1); + memcpy(env, ev, ev.GetCount() + 1); + if(CreateProcess(NULL, cmd, &sa, &sa, TRUE, + NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE, + ~env, NULL, &si, &pi)) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + else + PutConsole("Unable to launch " + String(_cmdline)); +#endif +#ifdef PLATFORM_POSIX + String script = ConfigFile("console-script-" + AsString(getpid()) + ".tmp"); + int c = LinuxHostConsole.FindFirstOf(" "); + String lc = c < 0 ? LinuxHostConsole : LinuxHostConsole.Left(c); + if(FileExists(lc)) { + + if(console) { + FileStream out(script, FileStream::CREATE, 0777); + out << "#!/bin/sh\n" + << cmdline << '\n' + << "echo \"<--- Finished, press any key to close the window --->\"\nread dummy\n"; + cmdline = LinuxHostConsole + " sh " + script; + } + } + else + if(LinuxHostConsole.GetCount()) + PutConsole("Warning: Terminal '" + lc + "' not found, executing in background."); + Buffer cmd_buf(strlen(cmdline) + 1); + char *cmd_out = cmd_buf; + Vector args; + const char *p = cmdline; + const char *b = p; + while(*p && (byte)*p > ' ') + if(*p++ == '\"') + while(*p && *p++ != '\"') + ; + args.Add(cmd_out); + memcpy(cmd_out, b, p - b); + cmd_out += p - b; + *cmd_out++ = '\0'; + + while(*p) + if((byte)*p <= ' ') + p++; + else { + args.Add(cmd_out); + b = p; + while(*p && (byte)*p > ' ') + if(*p++ == '\"') + { + memcpy(cmd_out, b, p - b - 1); + cmd_out += p - b - 1; + b = p; + while(*p && *p != '\"') + p++; + memcpy(cmd_out, b, p - b); + cmd_out += p - b; + if(*p == '\"') + p++; + b = p; + } + memcpy(cmd_out, b, p - b); + cmd_out += p - b; + *cmd_out++ = '\0'; + } + + args.Add(NULL); + + ONCELOCK { + struct sigaction sigchld_action; + memset(&sigchld_action, 0, sizeof(sigchld_action)); + sigchld_action.sa_handler = sCleanZombies; + sigaction(SIGCHLD, &sigchld_action, NULL); + } + + pid_t pid = fork(); + if(pid == 0) + { + const char *from = environment; + Vector env; + while(*from) { + env.Add(from); + from += strlen(from) + 1; + } + env.Add(NULL); + const char **envp = env.Begin(); + execve(args[0], args, (char *const *)envp); + abort(); + } + LLOG("Launch pid: " << pid); + sPid().Add(pid); +#endif +} + +void LocalHost::AddFlags(Index& cfg) +{ +#if defined(PLATFORM_WIN32) + cfg.Add("WIN32"); +#endif + +#ifdef PLATFORM_LINUX + cfg.Add("LINUX"); +#endif + +#ifdef PLATFORM_POSIX + cfg.Add("POSIX"); +#endif + +#ifdef PLATFORM_BSD + cfg.Add("BSD"); +#endif + +#ifdef PLATFORM_FREEBSD + cfg.Add("FREEBSD"); +#endif + +#ifdef PLATFORM_OPENBSD + cfg.Add("OPENBSD"); +#endif + +#ifdef PLATFORM_NETBSD + cfg.Add("NETBSD"); +#endif + +#ifdef PLATFORM_SOLARIS + cfg.Add("SOLARIS"); +#endif + +#ifdef PLATFORM_OSX11 + cfg.Add("OSX11"); +#endif +} + +static bool IsSamePath(const char *a, const char *b, int count) { + for(; --count >= 0; a++, b++) + if(a != b && ToLower(*a) != ToLower(*b) && !((*a == '\\' || *a == '/') && (*b == '\\' || *b == '/'))) + return false; + return true; +} + +#if 0 +String RemoteHost::GetEnvironment() +{ + return environment; +} + +String RemoteHost::GetHostPath(const String& path) +{ + bool slash = (os_type != "WINDOWS"); + for(int i = 0; i < path_map_local.GetCount(); i++) { + String lc = path_map_local[i]; + if(path.GetLength() >= lc.GetLength() && IsSamePath(path, lc, lc.GetLength())) + { + String r = CatAnyPath(path_map_remote[i], path.Mid(lc.GetLength())); + return slash ? UnixPath(r) : WinPath(r); + } + } + return slash ? UnixPath(path) : WinPath(path); +} + +String RemoteHost::GetLocalPath(const String& path) +{ + for(int i = 0; i < path_map_remote.GetCount(); i++) { + String rc = path_map_remote[i]; + if(path.GetLength() >= rc.GetLength() && IsSamePath(path, rc, rc.GetLength())) + return path_map_local[i] + path.Mid(rc.GetLength()); + } + if(!memcmp(path, "/cygdrive/", 10)) + { + const char *s = path.Begin() + 10; + String out; + if(*s) + out << *s++ << ':'; + out << s; + return out; + } + return NativePath(path); +} + +String RemoteHost::NormalizePath(const String& path) +{ + return path; +} + +String RemoteHost::RemoteExec(String cmd) +{ + Socket socket; + String sockerr; +/* + String hostname = host; + int port = 2346; + int ppos = hostname.Find(':'); + if(ppos >= 0) + { + port = atoi(host.GetIter(ppos + 1)); + hostname.Trim(ppos); + } +*/ + if(!ClientSocket(socket, host, port, true, NULL, 2000)) { + PutConsole(NFormat("Error connecting to '%s', port %d: %s", host, port, Socket::GetErrorText())); + return String::GetVoid(); + } + socket.Write(cmd); + socket.Write("\0", 1); + return socket.ReadUntil('\0', Null, 10000000); +} + +Vector RemoteHost::GetFileInfo(const Vector& path) +{ + VectorMap out; + out.Reserve(path.GetCount()); + String request; + request << "@" << (int)(GetSysTime() - TimeBase()) << ":"; + for(int i = 0; i < path.GetCount(); i++) + { + String hp = GetHostPath(path[i]); + request << hp << "\n"; + FileInfo& fi = out.Add(hp); + (Time&)fi = Time::Low(); + fi.length = Null; + } + String result = RemoteExec(request); + const char *p = result; + while(*p) + { + const char *b = p; + while(*p && *p != '\n' && *p != '\t') + p++; + String fn(b, p); + Time time = Time::Low(); + int size = Null; + if(*p == '\t') + { + int t = ScanInt(p + 1, &p); + if(!IsNull(t)) + time = TimeBase() + t; + if(*p == '\t') + size = ScanInt(p + 1, &p); + } + int ifn = out.Find(fn); + if(ifn >= 0) + { + (Time&)out[ifn] = time; + out[ifn].length = size; + } + while(*p && *p++ != '\n') + ; + } + return out.PickValues(); +} + +void RemoteHost::DeleteFile(const Vector& path) +{ + String request = "-"; + for(int i = 0; i < path.GetCount(); i++) + request << GetHostPath(path[i]) << "\n"; + String out = RemoteExec(request); + if(!IsNull(out) && out != "OK") + PutVerbose(out); +} + +void RemoteHost::DeleteFolderDeep(const String& folder) +{ + String out = RemoteExec("~" + GetHostPath(folder)); + if(out != "OK") + PutConsole(out); +} + +void RemoteHost::ChDir(const String& path) +{ + chdir_path = GetHostPath(path); +} + +void RemoteHost::RealizeDir(const String& path) +{ + RemoteExec("*" + GetHostPath(path)); +} + +void RemoteHost::SaveFile(const String& path, const String& data) +{ + String request; + request << ">" << GetHostPath(path) + << "\t" << int(GetSysTime() - TimeBase()) + << "\t" << data.GetLength() + << "\t" << ASCII85Encode(BZ2Compress(data)) + << "\n"; + String out = RemoteExec(request); + if(out != "OK") + PutConsole(out); +} + +String RemoteHost::LoadFile(const String& path) +{ + String hpath = GetHostPath(path); + String request = "^" + hpath; + String out = RemoteExec(request); + const char *p = out; + while(*p && *p != '\n' && *p != '\t') + p++; + if(*p++ != '\t') + return String::GetVoid(); + int len = ScanInt(p, &p); + if(IsNull(len) || len <= 0 || *p++ != '\t') + return String::GetVoid(); + String data = BZ2Decompress(ASCII85Decode(p)); + if(data.GetLength() != len) + { + PutConsole(NFormat("%s: decompressed length (%d) doesn't match length in header (%d)", + hpath, data.GetLength(), len)); + return String::GetVoid(); + } + return data; +} + +int RemoteHost::Execute(const char *cmdline) +{ + int q = IdeConsoleExecute(StartProcess(cmdline), cmdline); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int RemoteHost::ExecuteWithInput(const char *cmdline) +{ + int q = IdeConsoleExecute(StartProcess(cmdline), cmdline); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int RemoteHost::Execute(const char *cmdline, Stream& out) +{ + int q = IdeConsoleExecute(StartProcess(cmdline), cmdline, &out, true); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int RemoteHost::AllocSlot() +{ + return IdeConsoleAllocSlot(); +} + +bool RemoteHost::Run(const char *cmdline, int slot, String key, int blitz_count) +{ + return IdeConsoleRun(StartProcess(cmdline), cmdline, NULL, false, slot, key, blitz_count); +} + +bool RemoteHost::Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) +{ + return IdeConsoleRun(StartProcess(cmdline), cmdline, &out, false, slot, key, blitz_count); +} + +bool RemoteHost::Wait() +{ + return IdeConsoleWait(); +} + +One RemoteHost::StartProcess(const char *cmdline) +{ + try { + PutVerbose(cmdline); + return StartRemoteProcess(host, port, cmdline, environment, REMOTE_TIMEOUT); + } + catch(...) { + return NULL; + } +} + +void RemoteHost::Launch(const char *_cmdline, bool) +{ +} + +void RemoteHost::AddFlags(Index& cfg) +{ + cfg.Add(os_type); +} +#endif \ No newline at end of file diff --git a/uppsrc/ide/Core/Host.h b/uppsrc/ide/Core/Host.h index 090bebc4d..8ba601f5a 100644 --- a/uppsrc/ide/Core/Host.h +++ b/uppsrc/ide/Core/Host.h @@ -24,7 +24,7 @@ struct Host { virtual bool Run(const char *cmdline, int slot, String key, int blitz_count) = 0; virtual bool Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) = 0; virtual bool Wait() = 0; - virtual One StartProcess(const char *cmdline) = 0; + virtual One StartProcess(const char *cmdline) = 0; virtual void Launch(const char *cmdline, bool console = false) = 0; virtual void AddFlags(Index& cfg) = 0; @@ -56,11 +56,12 @@ struct LocalHost : Host { virtual bool Run(const char *cmdline, int slot, String key, int blitz_count); virtual bool Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count); virtual bool Wait(); - virtual One StartProcess(const char *cmdline); + virtual One StartProcess(const char *cmdline); virtual void Launch(const char *cmdline, bool console); virtual void AddFlags(Index& cfg); }; +/* struct RemoteHost : Host { String host; int port; @@ -91,9 +92,10 @@ struct RemoteHost : Host { virtual bool Run(const char *cmdline, int slot, String key, int blitz_count); virtual bool Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count); virtual bool Wait(); - virtual One StartProcess(const char *cmdline); + virtual One StartProcess(const char *cmdline); virtual void Launch(const char *cmdline, bool console); virtual void AddFlags(Index& cfg); String RemoteExec(String cmd); }; +*/ \ No newline at end of file diff --git a/uppsrc/ide/Debuggers/Debuggers.h b/uppsrc/ide/Debuggers/Debuggers.h index aae331f2a..a35847ef0 100644 --- a/uppsrc/ide/Debuggers/Debuggers.h +++ b/uppsrc/ide/Debuggers/Debuggers.h @@ -69,7 +69,7 @@ struct Dbg : Debugger, ParentCtrl { virtual bool IsFinished(); One host; - One dbg; + One dbg; FrameBottom > regs; diff --git a/uppsrc/ide/Debuggers/Gdb_MI2.h b/uppsrc/ide/Debuggers/Gdb_MI2.h index edb76f5fc..8a2812452 100644 --- a/uppsrc/ide/Debuggers/Gdb_MI2.h +++ b/uppsrc/ide/Debuggers/Gdb_MI2.h @@ -1,242 +1,242 @@ -#ifndef _ide_Debuggers_Gdb_MI2_h_ -#define _ide_Debuggers_Gdb_MI2_h_ - -#include "MIValue.h" - -class WatchEdit : public LineEdit -{ - virtual void HighlightLine(int line, Vector& h, int pos); -}; - -#define LAYOUTFILE -#include - -class Gdb_MI2 : public Debugger, public ParentCtrl -{ - private: - - One host; - One dbg; - - bool firstRun; - - // the disassembler window - DbgDisas disas; - - // the registers pane -#ifdef CPU_64 - FrameBottom > regs; -#define RPREFIX "r" -#else - FrameBottom > regs; -#define RPREFIX "e" -#endif - - // the quick watch dialog - WithGdb_MI2QuickwatchLayout quickwatch; - - EditString watchedit; - DropList frame; - DropList threadSelector; - TabCtrl tab; - ArrayCtrl locals; - ArrayCtrl watches; - ArrayCtrl autos; - - // explorer stuffs -- just starting - ArrayCtrl explorer; - EditString explorerExprEdit; - Button explorerBackBtn, explorerForwardBtn; - StaticRect explorerPane; - void onExploreExpr(ArrayCtrl *what = NULL); - void onExplorerChild(); - void onExplorerBack(); - void onExplorerForward(); - void ExplorerMenu(Bar& bar); - void doExplore(String const &expr, String var, bool isChild, bool appendHistory); - Index explorerHistoryExpressions; - Index explorerHistoryVars; - Vector explorerHistoryChilds; - int explorerHistoryPos; - Vector explorerChildVars; - String explorerParentExpr; - - Label dlock; - - Vector regname; - Vector