]> git.tdb.fi Git - builder.git/commitdiff
Rudimentary support for compiling things for Android
authorMikko Rasa <tdb@tdb.fi>
Fri, 3 Oct 2014 23:08:48 +0000 (02:08 +0300)
committerMikko Rasa <tdb@tdb.fi>
Fri, 3 Oct 2014 23:08:48 +0000 (02:08 +0300)
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.

12 files changed:
builderrc
source/androidccompiler.cpp [new file with mode: 0644]
source/androidccompiler.h [new file with mode: 0644]
source/androidcxxcompiler.cpp [new file with mode: 0644]
source/androidcxxcompiler.h [new file with mode: 0644]
source/androidlinker.cpp [new file with mode: 0644]
source/androidlinker.h [new file with mode: 0644]
source/androidtools.cpp [new file with mode: 0644]
source/androidtools.h [new file with mode: 0644]
source/architecture.cpp
source/architecture.h
source/builder.cpp

index c9133d0df496149822e5ce049f8778204d17316e..9be1df252f437e597ca707c92b5b0d453e615c70 100644 (file)
--- 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 (file)
index 0000000..8c9306e
--- /dev/null
@@ -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 (file)
index 0000000..f723a00
--- /dev/null
@@ -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 (file)
index 0000000..04970ad
--- /dev/null
@@ -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 (file)
index 0000000..e6c1478
--- /dev/null
@@ -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 (file)
index 0000000..8b7685b
--- /dev/null
@@ -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 (file)
index 0000000..5f30fcd
--- /dev/null
@@ -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 (file)
index 0000000..b89af6e
--- /dev/null
@@ -0,0 +1,133 @@
+#include <cstdlib>
+#include <msp/fs/dir.h>
+#include <msp/strings/lexicalcast.h>
+#include <msp/strings/utils.h>
+#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<string> toolchains = list_files(toolchains_dir);
+
+       string prefix = architecture.get_cross_prefix()+"-";
+       string use_toolchain;
+       unsigned latest_version = 0;
+       for(list<string>::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_str.size() && !isdigit(version_str[j])); ++j) ;
+                               compiler = version_str.substr(0, j);
+                               version_str = version_str.substr(j);
+                       }
+
+                       if(compiler!="gcc")
+                               continue;
+
+                       vector<string> version_parts = split(version_str, '.');
+                       unsigned version = (lexical_cast<unsigned>(version_parts[0])<<8);
+                       if(version_parts.size()>1)
+                               version += lexical_cast<unsigned>(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<string> tc_archs = list_files(toolchains_dir/use_toolchain/"prebuilt");
+       string use_arch;
+       for(list<string>::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<string> platforms = list_files(platforms_dir);
+
+       string use_platform;
+       unsigned highest_level = 0;
+       for(list<string>::const_iterator i=platforms.begin(); i!=platforms.end(); ++i)
+               if(!i->compare(0, 8, "android-"))
+               {
+                       unsigned level = lexical_cast<unsigned>(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<string> platform_archs = list_files(platforms_dir/use_platform);
+       string use_arch;
+       for(list<string>::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 (file)
index 0000000..3ccedcb
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef ANDROIDTOOLS_H_
+#define ANDROIDTOOLS_H_
+
+#include <msp/fs/path.h>
+#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
index 3905f40c872dcb7f04e6c05ed72a970dde31f2dd..07f5dbfb0c09159e7fa4fcbb14e7d9e3e6ff03af 100644 (file)
@@ -43,11 +43,13 @@ const char *systems[] =
        "freebsd",
        "darwin",
        "windows",
+       "android",
        0
 };
 
 const char *aliases[] =
 {
+       "x86",   "pc",
        "i586",  "pentium",
        "i686",  "pentiumpro",
        "x86_64", "athlon64",
index 4db809f19f3cbf0ef33e6706b8cc1bedae5f0619..cec397f8a29e1968a598d83abc949088a64d51ed 100644 (file)
@@ -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; }
index 3945b73333a4c6cb1d6995950c5a9197e48b2e0c..94acd45f8099f907f5650f1d1e19428be38a0c07 100644 (file)
@@ -9,6 +9,7 @@
 #include <msp/strings/format.h>
 #include <msp/time/units.h>
 #include <msp/time/utils.h>
+#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));