ultimatepp/uppsrc/ide/Methods.cpp
2026-04-18 13:42:22 +02:00

1008 lines
25 KiB
C++

#include <ide/Builders/AndroidBuilder.h>
#include "Methods.h"
void DirTable::SetData(const Value& data)
{
Vector<String> l = Split((String)data, ';');
Clear();
for(int i = 0; i < l.GetCount(); i++)
Add(l[i]);
}
Value DirTable::GetData() const
{
String s;
for(int i = 0; i < GetCount(); i++) {
if(i) s << ';';
s << (String)Get(i, 0);
}
return s;
}
void DirTable::Init(const char *name)
{
AutoHideSb();
AddColumn(name).Edit(edit);
Appending().Removing().Moving();
edit_dir.Attach(edit);
edit_dir.AllFilesType();
WhenArrayAction = edit <<= callback(this, &DirTable::Modify);
}
DirTable::DirTable()
{
Init();
NoHeader();
}
DirTable::DirTable(const char *name)
{
Init(name);
}
void DirMap::SetData(const Value& data)
{
Vector<String> l = Split((String)data, ';');
Clear();
for(int i = 0; i < l.GetCount(); i++) {
String li = l[i];
int f = li.Find('>');
if(f >= 0)
Add(li.Left(f), li.Mid(f + 1));
}
}
Value DirMap::GetData() const
{
String s;
for(int i = 0; i < GetCount(); i++) {
if(i) s << ';';
s << (String)Get(i, 0) << '>' << (String)Get(i, 1);
}
return s;
}
DirMap::DirMap()
{
AutoHideSb();
AddColumn("Map local path").Edit(localpath);
AddColumn("To remote path").Edit(remotepath);
Appending().Removing().Moving();
edit_dir.Attach(localpath);
WhenArrayAction = localpath <<= remotepath <<= callback(this, &DirMap::Modify);
}
void BuilderSetupInterface::InitBuilderSetup(BuilderSetup& bs)
{
bs.setupCtrl = this;
InitSetupCtrlsMap(bs.setupCtrlsMap);
}
AndroidBuilderSetup::AndroidBuilderSetup()
{
CtrlLayout(*this);
sdk_path << [=] { OnSdkPathChange(); };
sdk_path_download << [=] { LaunchWebBrowser(AndroidSDK::GetDownloadUrl()); };
sdk_path_download.SetImage(IdeImg::arrow_down());
DirSelect(sdk_path, sdk_path_select);
ndk_path << [=] { OnNdkPathChange(); };
ndk_path_download << [=] { LaunchWebBrowser(AndroidNDK::GetDownloadUrl()); };
ndk_path_download.SetImage(IdeImg::arrow_down());
DirSelect(ndk_path, ndk_path_select);
jdk_path_download << [=] { LaunchWebBrowser(Jdk::GetDownloadUrl()); };
jdk_path_download.SetImage(IdeImg::arrow_down());
DirSelect(jdk_path, jdk_path_select);
}
void AndroidBuilderSetup::InitSetupCtrlsMap(VectorMap<Id, Ctrl*>& map)
{
map.Add("SDK_PATH", &sdk_path);
map.Add("NDK_PATH", &ndk_path);
map.Add("JDK_PATH", &jdk_path);
map.Add("SDK_PLATFORM_VERSION", &sdk_platform_version);
map.Add("SDK_BUILD_TOOLS_RELEASE", &sdk_build_tools_release);
map.Add("NDK_BLITZ", &ndk_blitz);
map.Add("NDK_ARCH_ARMEABI_V7A", &ndk_arch_armeabi_v7a);
map.Add("NDK_ARCH_ARM64_V8A", &ndk_arch_arm64_v8a);
map.Add("NDK_ARCH_X86", &ndk_arch_x86);
map.Add("NDK_ARCH_X86_64", &ndk_arch_x86_64);
map.Add("NDK_TOOLCHAIN", &ndk_toolchain);
map.Add("NDK_CPP_RUNTIME", &ndk_cpp_runtime);
map.Add("NDK_COMMON_CPP_OPTIONS", &ndk_common_cpp_options);
map.Add("NDK_COMMON_C_OPTIONS", &ndk_common_c_options);
}
void AndroidBuilderSetup::New(const String& builder)
{
OnLoad();
}
void AndroidBuilderSetup::OnLoad()
{
OnSdkPathChange();
OnNdkPathChange();
}
void AndroidBuilderSetup::OnCtrlLoad(const String& ctrlKey, const String& value)
{
VectorMap<Id, Ctrl*> map;
InitSetupCtrlsMap(map);
if(map.Find(ctrlKey) > -1) {
Ctrl* ctrl = map.Get(ctrlKey);
if(ctrl == &sdk_path) {
OnSdkPathChange0(value);
}
else
if(ctrl == &ndk_path) {
OnNdkPathChange0(value);
}
}
}
void AndroidBuilderSetup::OnShow()
{
OnSdkShow();
OnNdkShow();
}
void AndroidBuilderSetup::OnSdkShow()
{
AndroidSDK sdk(sdk_path.GetData(), true);
if(!sdk.Validate()) {
DisableSdkCtrls();
return;
}
EnableSdkCtrls();
if(sdk_platform_version.GetValue().IsNull())
sdk_platform_version.SetData(sdk.FindDefaultPlatform());
if(sdk_build_tools_release.GetValue().IsNull())
sdk_build_tools_release.SetData(sdk.FindDefaultBuildToolsRelease());
}
void AndroidBuilderSetup::OnSdkPathInsert()
{
String currentPath = sdk_path.GetData();
InsertPath(&sdk_path);
String newPath = sdk_path.GetData();
if(currentPath != newPath)
OnSdkPathChange();
}
void AndroidBuilderSetup::OnSdkPathChange()
{
OnSdkPathChange0(sdk_path.GetData());
OnSdkShow();
}
void AndroidBuilderSetup::OnSdkPathChange0(const String& sdkPath)
{
AndroidSDK sdk(sdkPath, true);
if(sdk.Validate()) {
LoadPlatforms(sdk);
LoadBuildTools(sdk);
}
else
ClearSdkCtrls();
}
void AndroidBuilderSetup::OnNdkShow()
{
AndroidNDK ndk(ndk_path.GetData());
if(!ndk.Validate()) {
DisableNdkCtrls();
return;
}
EnableNdkCtrls();
}
void AndroidBuilderSetup::OnNdkPathInsert()
{
String currentPath = ndk_path.GetData();
InsertPath(&ndk_path);
String newPath = ndk_path.GetData();
if(currentPath != newPath)
OnNdkPathChange();
}
void AndroidBuilderSetup::OnNdkPathChange()
{
OnNdkPathChange0(ndk_path.GetData());
OnNdkShow();
}
void AndroidBuilderSetup::OnNdkPathChange0(const String& ndkPath)
{
AndroidNDK ndk(ndkPath);
if(ndk.Validate()) {
LoadToolchains(ndk);
LoadCppRuntimes(ndk);
ndk_arch_arm64_v8a.Set(1);
ndk_arch_x86_64.Set(1);
ndk_common_cpp_options.SetData("-std=c++17 -fexceptions -frtti -Wno-logical-op-parentheses");
}
else
ClearNdkCtrls();
}
void AndroidBuilderSetup::LoadPlatforms(const AndroidSDK& sdk)
{
Vector<String> platforms = sdk.FindPlatforms();
Sort(platforms, StdGreater<String>());
LoadDropList(sdk_platform_version,
platforms,
sdk.FindDefaultPlatform());
}
void AndroidBuilderSetup::LoadBuildTools(const AndroidSDK& sdk)
{
Vector<String> releases = sdk.FindBuildToolsReleases();
Sort(releases, StdGreater<String>());
LoadDropList(sdk_build_tools_release,
releases,
sdk.FindDefaultBuildToolsRelease());
}
void AndroidBuilderSetup::LoadToolchains(const AndroidNDK& ndk)
{
Vector<String> toolchains = ndk.FindToolchains();
Sort(toolchains, StdGreater<String>());
LoadDropList(ndk_toolchain, toolchains, ndk.FindDefaultToolchain());
}
void AndroidBuilderSetup::LoadCppRuntimes(const AndroidNDK& ndk)
{
Vector<String> runtimes = ndk.FindCppRuntimes();
LoadDropList(ndk_cpp_runtime, runtimes, ndk.FindDefaultCppRuntime());
}
void AndroidBuilderSetup::LoadDropList(
DropList& dropList,
const Vector<String>& values,
const String& defaultKey)
{
dropList.Clear();
for(int i = 0; i < values.GetCount(); i++)
dropList.Add(values[i]);
if(!defaultKey.IsEmpty() && dropList.GetCount()) {
int idx = dropList.Find(defaultKey);
if(idx >= 0)
dropList.SetIndex(idx);
}
}
void AndroidBuilderSetup::EnableSdkCtrls(bool enable)
{
sdk_platform_version.Enable(enable);
sdk_build_tools_release.Enable(enable);
}
void AndroidBuilderSetup::DisableSdkCtrls()
{
EnableSdkCtrls(false);
}
void AndroidBuilderSetup::ClearSdkCtrls()
{
sdk_platform_version.Clear();
sdk_build_tools_release.Clear();
}
void AndroidBuilderSetup::EnableNdkCtrls(bool enable)
{
ndk_blitz.Enable(enable);
ndk_arch_armeabi_v7a.Enable(enable);
ndk_arch_arm64_v8a.Enable(enable);
ndk_arch_x86.Enable(enable);
ndk_arch_x86_64.Enable(enable);
ndk_toolchain.Enable(enable);
ndk_cpp_runtime.Enable(enable);
ndk_common_cpp_options.Enable(enable);
ndk_common_c_options.Enable(enable);
}
void AndroidBuilderSetup::DisableNdkCtrls()
{
EnableNdkCtrls(false);
}
void AndroidBuilderSetup::ClearNdkCtrls()
{
ndk_blitz.Set(0);
ndk_arch_armeabi_v7a.Set(0);
ndk_arch_arm64_v8a.Set(0);
ndk_arch_x86.Set(0);
ndk_arch_x86_64.Set(0);
ndk_toolchain.Clear();
ndk_cpp_runtime.Clear();
ndk_common_cpp_options.Clear();
ndk_common_c_options.Clear();
}
DefaultBuilderSetup::DefaultBuilderSetup()
{
CtrlLayout(*this);
paths.Add(path.SizePos(), "PATH - executable directories");
paths.Add(include.SizePos(), "INCLUDE directories");
paths.Add(lib.SizePos(), "LIB directories");
debug_info.Add("0", "None");
debug_info.Add("1", "Minimal");
debug_info.Add("2", "Full");
}
void DefaultBuilderSetup::InitSetupCtrlsMap(VectorMap<Id, Ctrl*>& map)
{
map.Add("COMPILER", &compiler);
map.Add("COMMON_OPTIONS", &common_options);
map.Add("COMMON_CPP_OPTIONS", &common_cpp_options);
map.Add("COMMON_C_OPTIONS", &common_c_options);
map.Add("COMMON_LINK", &common_link_options);
map.Add("COMMON_FLAGS", &common_flags);
map.Add("DEBUG_INFO", &debug_info);
map.Add("DEBUG_BLITZ", &debug_blitz);
map.Add("DEBUG_LINKMODE", &debug_linkmode);
map.Add("DEBUG_OPTIONS", &debug_options);
map.Add("DEBUG_FLAGS", &debug_flags);
map.Add("DEBUG_LINK", &debug_link);
map.Add("DEBUG_CUDA", &debug_cuda);
map.Add("RELEASE_BLITZ", &release_blitz);
map.Add("RELEASE_LINKMODE", &release_linkmode);
map.Add("RELEASE_OPTIONS", &speed_options);
map.Add("RELEASE_FLAGS", &release_flags);
map.Add("RELEASE_LINK", &release_link);
map.Add("RELEASE_CUDA", &release_cuda);
map.Add("DEBUGGER", &debugger);
map.Add("ALLOW_PRECOMPILED_HEADERS", &allow_pch);
map.Add("DISABLE_BLITZ", &disable_blitz);
map.Add("PATH", &path);
map.Add("INCLUDE", &include);
map.Add("LIB", &lib);
}
void DefaultBuilderSetup::New(const String& builder)
{
bool gcc = findarg(builder, "GCC", "CLANG") >= 0;
if(IsNull(speed_options)) {
if(gcc)
speed_options <<= "-O3 -ffunction-sections -fdata-sections";
else
speed_options <<= "-O2";
}
if(IsNull(debug_options)) {
if(gcc)
debug_options <<= "-O0";
else
debug_options <<= "-Od";
}
if(IsNull(debugger)) {
if(gcc)
debugger <<= "gdb";
else
debugger <<= "msdev";
}
if(IsNull(release_link) && gcc)
release_link <<= "-Wl,--gc-sections";
}
int CharFilterFileName(int c)
{
return IsAlNum(c) || c == '_' ? c : 0;
}
BuildMethods::BuildMethods()
{
CtrlLayoutOKCancel(*this, "Build methods");
Sizeable().Zoomable();
method.AddColumn("Method").Edit(name);
name.SetFilter(CharFilterFileName);
method.AddCtrl("BUILDER", builder);
InitSetups();
method.AddCtrl("SCRIPT", scriptfile);
method.AddCtrl("LINKMODE_LOCK", linkmode_lock);
open_script.Attach(scriptfile);
open_script.Type("Build scripts (*.bsc)", "*.bsc")
.AllFilesType();
open_script.DefaultExt("bsc");
method.Appending().Removing().Duplicating();
method.WhenCursor = THISBACK(ChangeMethod);
method.WhenBar = THISBACK(MethodMenu);
for(int i = 0; i < BuilderMap().GetCount(); i++)
builder.Add(BuilderMap().GetKey(i));
builder <<= THISBACK(NewBuilder);
setdefault <<= THISBACK(SetDefault);
IdeHelpButton(help, "BuildMethods");
linkmode_lock.SetLabel("Lock link mode");
}
void BuildMethods::MethodMenu(Bar& bar)
{
method.StdBar(bar);
bar.Separator();
bar.Add("Import", THISBACK(Import));
}
void BuildMethods::Import()
{
if(!Save())
return;
FileSel fsel;
fsel.Type("Build methods (*.bm)", "*.bm")
.AllFilesType()
.Multi()
.DefaultExt("bm");
if(!fsel.ExecuteOpen())
return;
for(int i = 0; i < fsel.GetCount(); i++) {
String f = LoadFile(fsel[i]);
if(f.IsVoid()) {
if(!PromptOKCancel(Format("Failed to load [* \1%s\1]. Continue?", fsel[i])))
break;
continue;
}
String nf = ConfigFile(GetFileNamePos(fsel[i]));
if(FileExists(nf) && !PromptOKCancel(Format("File already exists: [* \1%s\1]. Overwrite?", nf)))
continue;
if(!SaveFile(nf, f))
if(!PromptOKCancel(Format("Failed to save [* \1%s\1]. Continue?", nf)))
break;
}
Load();
}
static int sCompare(const Value& v1, const Value& v2)
{
return (String)v1 < (String)v2;
}
void BuildMethods::NewBuilder()
{
String builderName = ~builder;
for(int i = 0; i < setups.GetCount(); i++) {
Index<String> currentBuilders = StringToBuilders(setups.GetKey(i));
if(currentBuilders.Find(builderName) > -1)
setups[i].setupCtrl->New(builderName);
}
SwitchSetupView();
}
void BuildMethods::ChangeMethod()
{
String b;
if(method.IsCursor())
b = method.Get("BUILDER");
scriptfile.Enable(b == "SCRIPT");
SwitchSetupView();
}
void BuildMethods::Load()
{
method.Clear();
FindFile ff(ConfigFile("*.bm"));
while(ff) {
VectorMap<String, String> map;
String fn = ConfigFile(ff.GetName());
if(LoadVarFile(fn, map)) {
String builderName = map.Get("BUILDER", Null);
int setupIdx = -1;
String prefix;
for(int i = 0; i < setups.GetCount(); i++) {
Index<String> currentBuilders = StringToBuilders(setups.GetKey(i));
prefix = GetSetupPrefix(currentBuilders);
if(currentBuilders.Find(builderName) >= 0) {
setupIdx = i;
break;
}
}
if(setupIdx >= 0)
setups[setupIdx].setupCtrl->OnLoad();
map = MapBuilderVars(map);
origfile.Add(fn);
method.Add(GetFileTitle(fn));
for(int j = 1; j < method.GetIndexCount(); j++) {
String key = method.GetId(j).ToString();
String val = map.Get(key, Null);
if(setupIdx >= 0) {
if(key.GetCount() >= prefix.GetCount())
key.Remove(0, prefix.GetCount());
setups[setupIdx].setupCtrl->OnCtrlLoad(key, val);
}
method.Set(method.GetCount() - 1, j, val);
}
}
ff.Next();
}
method.Sort(0, sCompare);
method.GoBegin();
}
bool BuildMethods::Save()
{
int i;
Index<String> name;
for(i = 0; i < method.GetCount(); i++) {
String n = method.Get(i, 0);
if(name.Find(n) >= 0) {
Exclamation("Duplicate method [* " + DeQtf(n) + "] !");
return false;
}
name.Add(n);
}
Index<String> saved;
for(i = 0; i < method.GetCount(); i++) {
VectorMap<String, String> map;
for(int j = 1; j < method.GetIndexCount(); j++)
map.Add(method.GetId(j).ToString(), method.Get(i, j));
if(map.Get("BUILDER", Null) != "SCRIPT")
map.RemoveKey("SCRIPT");
map = SieveBuilderVars(map);
String fn = ConfigFile(String(method.Get(i, 0)) + ".bm");
if(!SaveVarFile(fn, map)) {
Exclamation("Error saving [* " + fn + "] !");
return false;
}
saved.Add(fn);
}
for(i = 0; i < origfile.GetCount(); i++)
if(saved.Find(origfile[i]) < 0)
DeleteFile(origfile[i]);
return true;
}
void BuildMethods::ShowDefault()
{
String m = GetDefaultMethod();
for(int i = 0; i < method.GetCount(); i++)
if((String)method.Get(i, 0) == m)
method.SetDisplay(i, 0, BoldDisplay());
else
method.SetDisplay(i, 0, StdDisplay());
}
void BuildMethods::SetDefault()
{
if(method.IsCursor()) {
SaveFile(ConfigFile("default_method"), method.GetKey());
ShowDefault();
}
}
String BuildMethods::GetSetupPrefix(const String& setupKey) const
{
return setupKey + "_";
}
String BuildMethods::GetSetupPrefix(const Index<String>& buildersGroup) const
{
return buildersGroup.GetCount() ? GetSetupPrefix(buildersGroup[0]) : String();
}
void BuildMethods::InitSetups()
{
Index<String> builders = GetBuilders();
String androidKey = BuildersToString(AndroidBuilder::GetBuildersNames());
androidSetup.InitBuilderSetup(setups.Add(androidKey));
SieveBuilders(builders, AndroidBuilder::GetBuildersNames());
String defaultKey = BuildersToString(builders);
defaultSetup.InitBuilderSetup(setups.Add(defaultKey));
for(int i = 0; i < setups.GetCount(); i++) {
Index<String> currentBuilders = StringToBuilders(setups.GetKey(i));
if(currentBuilders.IsEmpty())
continue;
String setupKey = currentBuilders[0];
ParentCtrl *currentSetup = setups[i].setupCtrl;
setup.Add(currentSetup->SizePos());
currentSetup->Hide();
for(int j = 0; j < setups[i].setupCtrlsMap.GetCount(); j++) {
String ctrlKey = setups[i].setupCtrlsMap.GetKey(j);
Ctrl* ctrl = setups[i].setupCtrlsMap[j];
method.AddCtrl(GetSetupPrefix(setupKey) + ctrlKey, *ctrl);
}
}
}
void BuildMethods::SwitchSetupView()
{
if(!method.IsCursor()) {
builder.Hide();
builderLabel.Hide();
setup.Hide();
return;
}
else {
builder.Show();
builderLabel.Show();
}
String builderName = ~builder;
builderName.IsEmpty() ? setup.Hide() : setup.Show();
if(!builderName.IsEmpty()) {
for(int i = 0; i < setups.GetCount(); i++) {
Index<String> currentBuilders = StringToBuilders(setups.GetKey(i));
if(currentBuilders.Find(builderName) > -1) {
setups[i].setupCtrl->Show();
setups[i].setupCtrl->OnShow();
}
else
setups[i].setupCtrl->Hide();
}
}
}
VectorMap<String, String> BuildMethods::SieveBuilderVars(const VectorMap<String, String>& map)
{
VectorMap<String, String> sievedMap;
String builder = map.Get("BUILDER", Null);
if(builder.IsEmpty())
return VectorMap<String, String>();
for(int i = 0; i < map.GetCount(); i++) {
String key = map.GetKey(i);
String value = map[i];
bool toInsert = true;
for(int j = 0; j < setups.GetCount(); j++) {
Index<String> currentBuilders = StringToBuilders(setups.GetKey(j));
if(currentBuilders.IsEmpty())
continue;
String prefix = GetSetupPrefix(currentBuilders[0]);
if(key.StartsWith(prefix)) {
if(currentBuilders.Find(builder) > -1)
key.Remove(0, prefix.GetCount());
else
toInsert = false;
}
}
if(toInsert)
sievedMap.Add(key, value);
}
return sievedMap;
}
VectorMap<String, String> BuildMethods::MapBuilderVars(const VectorMap<String, String>& map)
{
VectorMap<String, String> mapedMap;
Index<String> varsToMaped;
String builder = map.Get("BUILDER", Null);
if(builder.IsEmpty())
return VectorMap<String, String>();
for(int i = 0; i < setups.GetCount(); i++) {
Index<String> currentBuilders = StringToBuilders(setups.GetKey(i));
if(currentBuilders.IsEmpty())
continue;
if(currentBuilders.Find(builder) >= 0) {
String setupPrefix = GetSetupPrefix(currentBuilders);
for(int j = 0; j < map.GetCount(); j++) {
String ctrlName = map.GetKey(j);
if(setups[i].setupCtrlsMap.Find(ctrlName) > -1)
mapedMap.Add(setupPrefix + ctrlName, map[j]);
else
mapedMap.Add(ctrlName, map[j]);
}
}
}
return mapedMap;
}
void BuildMethods::SieveBuilders(Index<String>& sievedBuilders,
const Index<String>& builders) const
{
for(int i = 0; i < builders.GetCount(); i++)
sievedBuilders.RemoveKey(builders[i]);
}
String BuildMethods::BuildersToString(const Index<String>& builders) const
{
String str;
for(int i = 0; i < builders.GetCount(); i++) {
str << builders[i];
if(i + 1 < builders.GetCount())
str << " ";
}
return str;
}
Index<String> BuildMethods::StringToBuilders(const String& str) const
{
Vector<String> vec = Split(str, ' ');
Index<String> builders;
for(int i = 0; i < vec.GetCount(); i++)
builders.Add(vec[i]);
return builders;
}
Index<String> BuildMethods::GetBuilders() const
{
Index<String> builders;
for(int i = 0; i < BuilderMap().GetCount(); i++)
builders.Add(BuilderMap().GetKey(i));
return builders;
}
void Ide::SetupBuildMethods()
{
BuildMethods m;
m.Load();
m.ShowDefault();
m.use_target = use_target;
m.method.FindSetCursor(method);
for(;;) {
int c = m.Run();
if(c == IDCANCEL)
break;
if(c == IDOK && m.Save()) {
use_target = m.use_target;
break;
}
}
InvalidateIncludes();
SyncBuildMode();
SetBar();
TriggerIndexer();
editor.TriggerSyncFile(0);
}
void ExtractIncludes(Index<String>& r, String h)
{
#ifdef PLATFORM_WIN32
h.Replace("\r", "");
#endif
Vector<String> ln = Split(h, '\n');
for(int i = 0; i < ln.GetCount(); i++) {
String dir = TrimBoth(ln[i]);
if(DirectoryExists(dir))
r.FindAdd(NormalizePath(dir));
}
}
String Ide::GetExternalIncludePath()
{
SetupDefaultMethod();
VectorMap<String, String> bm = GetMethodVars(method);
String include_path = bm.Get("INCLUDE", "");
#ifdef PLATFORM_POSIX
static String sys_includes;
ONCELOCK {
Index<String> r;
for(int pass = 0; pass < 2; pass++)
ExtractIncludes(r, HostSys(pass ? "clang -v -x c++ -E /dev/null" : "gcc -v -x c++ -E /dev/null"));
r.FindAdd("/usr/include_path");
r.FindAdd("/usr/local/include_path");
sys_includes = Join(r.GetKeys(), ";");
}
if(findarg(bm.Get("BUILDER", ""), "GCC", "CLANG") >= 0)
MergeWith(include_path, ";", sys_includes);
#endif
#ifdef PLATFORM_WIN32
static VectorMap<String, String> clang_include;
int q = clang_include.Find(method);
if(q < 0) {
String gcc = GetFileOnPath("clang.exe", bm.Get("PATH", "")); // TODO clang
Index<String> r;
if(gcc.GetCount()) {
String dummy = ConfigFile("dummy.cpp");
Upp::SaveFile(dummy, String());
VectorMap<String, String> env(Environment(), 1);
env.GetAdd("PATH") = Join(SplitDirs(bm.Get("PATH", "") + ';' + env.Get("PATH", "")), ";");
String environment;
for(int i = 0; i < env.GetCount(); i++)
environment << env.GetKey(i) << '=' << env[i] << '\0';
environment.Cat(0);
LocalProcess p;
String out;
if(p.Start(gcc + " -v -x c++ -E " + dummy, environment) && p.Finish(out) == 0)
ExtractIncludes(r, out);
DeleteFile(dummy);
}
q = clang_include.GetCount();
clang_include.Add(method, Join(r.GetKeys(), ";"));
}
MergeWith(include_path, ";", clang_include[q]);
#endif
if(findarg(bm.Get("BUILDER", ""), "ANDROID") >= 0) {
AndroidNDK ndk(bm.Get("NDK_PATH", ""));
if(ndk.Validate()) {
MergeWith(include_path, ";", ndk.GetIncludeDir());
String cppIncludeDir = ndk.GetCppIncludeDir(bm.Get("NDK_CPP_RUNTIME", ""));
if(!cppIncludeDir.IsEmpty()) {
MergeWith(include_path, ";", cppIncludeDir);
}
}
}
return include_path;
}
String Ide::GetIncludePath()
{
// this is 'real' include path defined by current build method, for Alt+J and #include assist
if(include_path.GetCount())
return include_path;
SetupDefaultMethod();
VectorMap<String, String> bm = GetMethodVars(method);
include_path = Join(GetUppDirs(), ";");
MergeWith(include_path, ";", GetExternalIncludePath());
String include_path = GetExternalIncludePath();
IncludeAddPkgConfig(include_path, Null);
return include_path;
}
void Ide::IncludeAddPkgConfig(String& include_path, const String& clang_method)
{
#ifdef PLATFORM_POSIX
const Workspace& wspc = GetIdeWorkspace();
Host host;
if(clang_method.GetCount())
CreateHost(host, clang_method, false, false, 0);
else
CreateHost(host, false, false);
One<Builder> b = CreateBuilder(&host);
Index<String> pkg_config;
Index<String> cfg = PackageConfig(wspc, max(GetPackageIndex(), 0), GetMethodVars(method), mainconfigparam, host, *b);
String main_conf;
for(int i = 0; i < wspc.GetCount(); i++) {
const Package& pkg = wspc.GetPackage(i);
for(int j = 0; j < pkg.include.GetCount(); j++) {
MergeWith(include_path, ";", SourcePath(wspc[i], pkg.include[j].text));
}
for(String h : Split(Gather(pkg.pkg_config, cfg.GetKeys()), ' '))
pkg_config.FindAdd(h);
}
static VectorMap<String, String> cflags;
for(String s : pkg_config) {
int q = cflags.Find(s);
if(q < 0) {
q = cflags.GetCount();
cflags.Add(s, HostSys("pkg-config --cflags " + s));
}
for(String p : Split(cflags[q], CharFilterWhitespace)) {
if(p.TrimStart("-I")) {
#ifdef FLATPAK
p.Replace("/usr", "/run/host/usr");
#endif
MergeWith(include_path, ";", p);
}
}
}
#endif
}
void AddDirs(String& include_path, const String& dir)
{
MergeWith(include_path, ";", dir);
for(FindFile ff(dir + "/*.*"); ff; ff.Next())
if(ff.IsFolder())
AddDirs(include_path, ff.GetPath());
}
String Ide::GetCurrentIncludePath()
{ // this is include path for libclang / assist
String include_path;
static String clang_method;
if(IsNull(clang_method)) {
String exact, x64, clang;
for(FindFile ff(ConfigFile(GetMethodName("*"))); ff; ff.Next()) {
String n = ToLower(GetFileTitle(ff.GetName()));
if(n == "clangx64")
exact = n;
if(n.StartsWith("clangx64"))
x64 = n;
if(n.StartsWith("clang"))
clang = n;
}
clang_method = Nvl(exact, x64, clang);
}
VectorMap<String, String> bm;
if(clang_method.GetCount())
bm = GetMethodVars(clang_method);
include_path = Join(GetUppDirs(), ";") + ';';
MergeWith(include_path, ";", GetVarsIncludes());
String inc1 = bm.Get("INCLUDE", "");
MergeWith(include_path, ";", inc1);
IncludeAddPkgConfig(include_path, clang_method);
String main_conf;
const Workspace& wspc = AssistWorkspace();
for(int i = 0; i < wspc.GetCount(); i++) {
const Package& pkg = wspc.GetPackage(i);
for(int j = 0; j < pkg.GetCount(); j++)
if(pkg[j] == "import.ext")
AddDirs(include_path, PackageDirectory(wspc[i]));
}
::MainConf(wspc, include_path);
for(int i = 0; i < wspc.GetCount(); i++) { // internal includes
const Package& pkg = wspc.GetPackage(i);
for(int j = 0; j < pkg.include.GetCount(); j++)
MergeWith(include_path, ";", SourcePath(wspc[i], pkg.include[j].text));
if(IsExternalMode()) // just add everything..
MergeWith(include_path, ";", PackageDirectory(wspc[i]));
}
return include_path;
}
String Ide::GetCurrentDefines()
{
Index<String> flags;
flags = SplitFlags(mainconfigparam, false);
AddHostFlags(flags);
String r;
for(String s : flags)
MergeWith(r, ";", "flag" + s);
const Workspace& wspc = AssistWorkspace();
for(int i = 0; i < wspc.GetCount(); i++) {
const Package& pkg = wspc.GetPackage(i);
for(int j = 0; j < pkg.GetCount(); j++) {
if(pkg[j] == "main.conf") {
MergeWith(r, ";", "MAIN_CONF");
return r;
}
}
}
return r;
}
String Ide::IdeGetIncludePath()
{
return GetIncludePath();
}