From: Mikko Rasa Date: Fri, 3 Oct 2014 23:08:48 +0000 (+0300) Subject: Rudimentary support for compiling things for Android X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=cee450d7cc932811b0d119a132bc9981eb480584;p=builder.git Rudimentary support for compiling things for Android At the moment programs are compiled as if for a desktop system. Creating graphical applications in this way is difficult, as it requires different build rules to compile the application code as a .so and some boilerplate to wrap it in a .apk with a NativeActivity. --- diff --git a/builderrc b/builderrc index c9133d0..9be1df2 100644 --- a/builderrc +++ b/builderrc @@ -1,4 +1,4 @@ -architecture "arm" +architecture "arm-linux" { prefix "arm-linux-gnueabi"; }; @@ -8,6 +8,11 @@ architecture "windows" prefix "i586-mingw32msvc"; }; +architecture "arm-android" +{ + prefix "arm-linux-androideabi"; +}; + build_type "debug" { build_info diff --git a/source/androidccompiler.cpp b/source/androidccompiler.cpp new file mode 100644 index 0000000..8c9306e --- /dev/null +++ b/source/androidccompiler.cpp @@ -0,0 +1,9 @@ +#include "androidccompiler.h" +#include "androidtools.h" + +AndroidCCompiler::AndroidCCompiler(Builder &b, const Architecture &a, const AndroidNdk &ndk): + GnuCCompiler(b, a, ndk.get_platform_sysroot()) +{ + set_command((ndk.get_bin_dir()/command).str()); + build_info.incpath.insert(build_info.incpath.end(), system_path.begin(), system_path.end()); +} diff --git a/source/androidccompiler.h b/source/androidccompiler.h new file mode 100644 index 0000000..f723a00 --- /dev/null +++ b/source/androidccompiler.h @@ -0,0 +1,14 @@ +#ifndef ANDROIDCCOMPILER_H_ +#define ANDROIDCCOMPILER_H_ + +#include "gnuccompiler.h" + +class AndroidNdk; + +class AndroidCCompiler: public GnuCCompiler +{ +public: + AndroidCCompiler(Builder &, const Architecture &, const AndroidNdk &); +}; + +#endif diff --git a/source/androidcxxcompiler.cpp b/source/androidcxxcompiler.cpp new file mode 100644 index 0000000..04970ad --- /dev/null +++ b/source/androidcxxcompiler.cpp @@ -0,0 +1,40 @@ +#include "androidcxxcompiler.h" +#include "androidtools.h" +#include "architecture.h" + +using namespace std; +using namespace Msp; + +AndroidCxxCompiler::AndroidCxxCompiler(Builder &b, const Architecture &a, const AndroidNdk &n): + GnuCxxCompiler(b, a, n.get_platform_sysroot()), + ndk(n) +{ + set_command((ndk.get_bin_dir()/command).str()); + build_info.incpath.insert(build_info.incpath.end(), system_path.begin(), system_path.end()); + build_info.libs.push_back("gnustl_shared"); +} + +void AndroidCxxCompiler::do_prepare() +{ + GnuCxxCompiler::do_prepare(); + if(executable) + { + FS::Path libstdcxx_path = ndk.get_root_dir()/"sources"/"cxx-stl"/"gnu-libstdc++"/version; + + /* TODO Match against architecture. Armeabi-v7a is problematic. + Architecture currently has no provisions for ABI, and the gcc -march + flag for ARMv7-A contains a dash. */ + string subdir; + if(architecture->get_type()=="pc") + subdir = "x86"; + else if(architecture->get_type()=="arm") + subdir = "armeabi-v7a"; + + SearchPath incpath; + incpath.push_back(libstdcxx_path/"include"); + incpath.push_back(libstdcxx_path/"libs"/subdir/"include"); + system_path.insert(system_path.end(), incpath.begin(), incpath.end()); + build_info.incpath.insert(build_info.incpath.end(), incpath.begin(), incpath.end()); + build_info.libpath.push_back(libstdcxx_path/"libs"/subdir); + } +} diff --git a/source/androidcxxcompiler.h b/source/androidcxxcompiler.h new file mode 100644 index 0000000..e6c1478 --- /dev/null +++ b/source/androidcxxcompiler.h @@ -0,0 +1,20 @@ +#ifndef ANDROIDCXXCOMPILER_H_ +#define ANDROIDCXXCOMPILER_H_ + +#include "gnucxxcompiler.h" + +class AndroidNdk; + +class AndroidCxxCompiler: public GnuCxxCompiler +{ +private: + const AndroidNdk &ndk; + +public: + AndroidCxxCompiler(Builder &, const Architecture &, const AndroidNdk &); + +protected: + virtual void do_prepare(); +}; + +#endif diff --git a/source/androidlinker.cpp b/source/androidlinker.cpp new file mode 100644 index 0000000..8b7685b --- /dev/null +++ b/source/androidlinker.cpp @@ -0,0 +1,9 @@ +#include "androidlinker.h" +#include "androidtools.h" + +AndroidLinker::AndroidLinker(Builder &b, const Architecture &a, const AndroidNdk &ndk): + GnuLinker(b, a, ndk.get_platform_sysroot()) +{ + set_command((ndk.get_bin_dir()/command).str()); + build_info.libpath.insert(build_info.libpath.end(), system_path.begin(), system_path.end()); +} diff --git a/source/androidlinker.h b/source/androidlinker.h new file mode 100644 index 0000000..5f30fcd --- /dev/null +++ b/source/androidlinker.h @@ -0,0 +1,14 @@ +#ifndef ANDROIDLINKER_H_ +#define ANDROIDLINKER_H_ + +#include "gnulinker.h" + +class AndroidNdk; + +class AndroidLinker: public GnuLinker +{ +public: + AndroidLinker(Builder &, const Architecture &, const AndroidNdk &); +}; + +#endif diff --git a/source/androidtools.cpp b/source/androidtools.cpp new file mode 100644 index 0000000..b89af6e --- /dev/null +++ b/source/androidtools.cpp @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include "androidccompiler.h" +#include "androidcxxcompiler.h" +#include "androidlinker.h" +#include "androidtools.h" +#include "architecture.h" +#include "builder.h" + +using namespace std; +using namespace Msp; + +AndroidTools::AndroidTools(Builder &builder, const Architecture &arch): + ndk(builder, arch) +{ + add_tool(new AndroidCCompiler(builder, arch, ndk)); + add_tool(new AndroidCxxCompiler(builder, arch, ndk)); + add_tool(new AndroidLinker(builder, arch, ndk)); +} + + +AndroidNdk::AndroidNdk(Builder &b, const Architecture &a): + builder(b), + architecture(a) +{ + if(const char *env_ndk_root = getenv("ANDROID_NDK_ROOT")) + ndk_root = env_ndk_root; + else + throw runtime_error("ANDROID_NDK_ROOT must be set"); + + find_toolchain_dir(); + find_platform_dir(); +} + +void AndroidNdk::find_toolchain_dir() +{ + FS::Path toolchains_dir = ndk_root/"toolchains"; + list toolchains = list_files(toolchains_dir); + + string prefix = architecture.get_cross_prefix()+"-"; + string use_toolchain; + unsigned latest_version = 0; + for(list::const_iterator i=toolchains.begin(); i!=toolchains.end(); ++i) + if(!i->compare(0, prefix.size(), prefix)) + { + string version_str = i->substr(prefix.size()); + string compiler = "gcc"; + if(!isdigit(version_str[0])) + { + unsigned j; + for(j=1; (j version_parts = split(version_str, '.'); + unsigned version = (lexical_cast(version_parts[0])<<8); + if(version_parts.size()>1) + version += lexical_cast(version_parts[1]); + + if(version>latest_version) + { + use_toolchain = *i; + latest_version = version; + } + } + + if(use_toolchain.empty()) + throw runtime_error("No applicable toolchains found"); + + const Architecture &native_arch = builder.get_native_arch(); + + list tc_archs = list_files(toolchains_dir/use_toolchain/"prebuilt"); + string use_arch; + for(list::const_iterator i=tc_archs.begin(); i!=tc_archs.end(); ++i) + { + string tca = *i; + for(string::iterator j=tca.begin(); j!=tca.end(); ++j) + if(*j=='_') + *j = '-'; + if(native_arch.match_name(tca)) + { + use_arch = *i; + break; + } + } + + if(use_arch.empty()) + throw runtime_error("No matching toolchain found"); + + bin_dir = toolchains_dir/use_toolchain/"prebuilt"/use_arch/"bin"; +} + +void AndroidNdk::find_platform_dir() +{ + FS::Path platforms_dir = ndk_root/"platforms"; + list platforms = list_files(platforms_dir); + + string use_platform; + unsigned highest_level = 0; + for(list::const_iterator i=platforms.begin(); i!=platforms.end(); ++i) + if(!i->compare(0, 8, "android-")) + { + unsigned level = lexical_cast(i->substr(8)); + if(level>highest_level) + { + use_platform = *i; + highest_level = level; + } + } + + if(use_platform.empty()) + throw runtime_error("No applicable platforms found"); + + list platform_archs = list_files(platforms_dir/use_platform); + string use_arch; + for(list::const_iterator i=platform_archs.begin(); i!=platform_archs.end(); ++i) + if(!i->compare(0, 5, "arch-") && architecture.match_name(i->substr(5))) + { + use_arch = *i; + break; + } + + if(use_arch.empty()) + throw runtime_error("No matching platform found"); + + platform_sysroot = platforms_dir/use_platform/use_arch; +} diff --git a/source/androidtools.h b/source/androidtools.h new file mode 100644 index 0000000..3ccedcb --- /dev/null +++ b/source/androidtools.h @@ -0,0 +1,42 @@ +#ifndef ANDROIDTOOLS_H_ +#define ANDROIDTOOLS_H_ + +#include +#include "toolchain.h" + +class Architecture; +class Builder; + +class AndroidNdk +{ +private: + Builder &builder; + const Architecture &architecture; + Msp::FS::Path ndk_root; + Msp::FS::Path bin_dir; + Msp::FS::Path platform_sysroot; + +public: + AndroidNdk(Builder &, const Architecture &); + +private: + void find_toolchain_dir(); + void find_platform_dir(); + +public: + const Msp::FS::Path &get_root_dir() const { return ndk_root; } + const Msp::FS::Path &get_bin_dir() const { return bin_dir; } + const Msp::FS::Path &get_platform_sysroot() const { return platform_sysroot; } +}; + + +class AndroidTools: public Toolchain +{ +private: + AndroidNdk ndk; + +public: + AndroidTools(Builder &, const Architecture &); +}; + +#endif diff --git a/source/architecture.cpp b/source/architecture.cpp index 3905f40..07f5dbf 100644 --- a/source/architecture.cpp +++ b/source/architecture.cpp @@ -43,11 +43,13 @@ const char *systems[] = "freebsd", "darwin", "windows", + "android", 0 }; const char *aliases[] = { + "x86", "pc", "i586", "pentium", "i686", "pentiumpro", "x86_64", "athlon64", diff --git a/source/architecture.h b/source/architecture.h index 4db809f..cec397f 100644 --- a/source/architecture.h +++ b/source/architecture.h @@ -38,6 +38,7 @@ private: public: Architecture(Builder &b, const std::string &spec); + const std::string &get_type() const { return type; } const std::string &get_name() const { return name; } const std::string &get_system() const { return system; } unsigned get_bits() const { return bits; } diff --git a/source/builder.cpp b/source/builder.cpp index 3945b73..94acd45 100644 --- a/source/builder.cpp +++ b/source/builder.cpp @@ -9,6 +9,7 @@ #include #include #include +#include "androidtools.h" #include "binarypackage.h" #include "builder.h" #include "builtintools.h" @@ -78,6 +79,8 @@ void Builder::add_default_tools() { if(current_arch->get_system()=="darwin") toolchain.add_toolchain(new ClangTools(*this, *current_arch)); + if(current_arch->get_system()=="android") + toolchain.add_toolchain(new AndroidTools(*this, *current_arch)); toolchain.add_toolchain(new GnuTools(*this, *current_arch)); toolchain.add_toolchain(new BuiltinTools(*this)); toolchain.add_tool(new DataTool(*this));