Merge: ldflags for Android
authorJean Privat <jean@pryen.org>
Thu, 29 Jan 2015 11:59:01 +0000 (18:59 +0700)
committerJean Privat <jean@pryen.org>
Thu, 29 Jan 2015 11:59:01 +0000 (18:59 +0700)
For the same module, cflags and ldflags can vary per platform. This new annotation on annotations targets a platform for each cflags or ldflags. By default, the target platform is that of the host. It will probably need to be clarified on more modules once we support more platforms.

It will be used to load (or not load) OpenGL ES v1.0 vs 2.0 and libandroid in future PR. For now, only `calculator` should save on linking with OpenGL.

I hesitated between different annotations before settling on `@android`:
* `@target(android)` makes it clear that it is the target, but it gets a bit heavy to read: `module android_opengles1 is ldflags("-lEGL -lGLESv1_CM")@target(android)`
* `@only(android)` makes it clear that only Android is affected by this annotation.
* but `@android` is easy to read and clear enough to fit with an already complex syntax.

TODO `cflags@android` declarations are accepted but unused at this time.

Pull-Request: #1124
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

21 files changed:
lib/android/aware.nit [new file with mode: 0644]
lib/android/log.nit
lib/android/native_app_glue.nit
lib/android/platform.nit
lib/egl.nit
lib/glesv2/glesv2.nit
lib/mnit_android/android_assets.nit
lib/mnit_android/android_opengles1.nit
src/c_tools.nit
src/compiler/abstract_compiler.nit
src/compiler/compiler_ffi.nit
src/ffi/c.nit
src/ffi/c_compiler_options.nit
src/ffi/cpp.nit
src/ffi/ffi.nit
src/ffi/java.nit
src/ffi/objc.nit
src/platform/android.nit
src/platform/emscripten.nit
src/platform/platform.nit
src/platform/pnacl.nit

diff --git a/lib/android/aware.nit b/lib/android/aware.nit
new file mode 100644 (file)
index 0000000..92a3a80
--- /dev/null
@@ -0,0 +1,20 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Android compatibility module
+#
+# Defines the `@android` annotation used to tag `ldflags` annotations.
+module aware is new_annotation(android)
index 30beb62..c165331 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 # Advanced Android logging services
-module log
+module log is ldflags "-llog"
 
 import platform
 
index af3c797..4ae4753 100644 (file)
@@ -36,7 +36,7 @@
 #   which is a subclass of `Activity` and `Context` (in Java). It represent
 #   main activity of the running application. Use it to get anything related
 #   to the `Context` and as anchor to execute Java UI code.
-module native_app_glue
+module native_app_glue is ldflags "-landroid"
 
 import platform
 import log
index fca03e0..7c15af5 100644 (file)
@@ -27,3 +27,4 @@ end
 
 import java
 import app
+import aware
index 4c24b57..b664c8a 100644 (file)
 # C library. If a method or class is not documented in Nit, refer to
 # the official documentation by the Khronos Group at:
 # http://www.khronos.org/registry/egl/sdk/docs/man/xhtml/
-module egl is pkgconfig
+module egl is
+       pkgconfig
+       ldflags("-lEGL")@android
+end
+
+import android::aware
 
 in "C Header" `{
        #include <EGL/egl.h>
index 06803ae..ca7faf1 100644 (file)
@@ -33,8 +33,10 @@ module glesv2 is
        pkgconfig
        new_annotation glsl_vertex_shader
        new_annotation glsl_fragment_shader
+       ldflags("-lGLESv2")@android
 end
 
+import android::aware
 
 in "C Header" `{
        #include <GLES2/gl2.h>
index 2c703bb..8f61c90 100644 (file)
@@ -21,7 +21,7 @@
 # * The Android ndk
 # * zlib (which is included in the Android ndk)
 # * libpng which must be provided by the Nit compilation framework
-module android_assets
+module android_assets is ldflags "-lz"
 
 import mnit
 import android_app
index 5996214..5ff9e7c 100644 (file)
@@ -16,7 +16,7 @@
 
 # Adapts OpenGL ES 1.0 for use on Android by offering services to get
 # a handler to the native display and window.
-module android_opengles1
+module android_opengles1 is ldflags "-lEGL -lGLESv1_CM"
 
 import android_app
 import android
index b835f2a..6fa1f05 100644 (file)
@@ -125,7 +125,7 @@ end
 class ExternCFile
        super ExternFile
 
-       # Additional specific CC compiler -c flags
+       # Custom options for the C compiler (CFLAGS)
        var cflags: String
 
        redef fun hash do return filename.hash
index dfe463c..b1a5879 100644 (file)
@@ -2990,7 +2990,7 @@ redef class MModule
 
        # Give requided addinional system libraries (as given to LD_LIBS)
        # Note: can return null instead of an empty set
-       fun collect_linker_libs: nullable Set[String] do return null
+       fun collect_linker_libs: nullable Array[String] do return null
 end
 
 # Create a tool context to handle options and paths
index ac7bad3..dea917b 100644 (file)
@@ -49,6 +49,7 @@ extern void nitni_global_ref_incr(void*);
 extern void nitni_global_ref_decr(void*);
 """
 
+               var cflags = self.cflags[""].join(" ")
                nitni_ccu.write_as_nitni(self, v.compiler.modelbuilder.compile_dir)
 
                for file in nitni_ccu.files do
@@ -76,11 +77,8 @@ extern void nitni_global_ref_decr(void*);
 
        redef fun collect_linker_libs
        do
-               var s = ldflags
-               if s.is_empty then return null
-               var res = new ArraySet[String]
-               res.add s
-               return res
+               if not self.ldflags.keys.has("") then return null
+               return self.ldflags[""]
        end
 
        private var compiled_callbacks = new Array[NitniCallback]
index 1790f48..495d4e6 100644 (file)
@@ -74,8 +74,14 @@ redef class Location
 end
 
 redef class MModule
-       var cflags = "" is writable
-       var ldflags = "" is writable
+       # FIXME make nullable the key of `cflags`, `ldflags` and `cppflags` when
+       # supported by the bootstrap
+
+       # Custom options for the C compiler (CFLAGS)
+       var cflags = new MultiHashMap[String, String]
+
+       # Custom options for the C linker (LDFLAGS)
+       var ldflags = new MultiHashMap[String, String]
 
        # Additional libraries needed for the compilation
        # Will be used with pkg-config
index e4756a8..4fbd5c4 100644 (file)
@@ -22,9 +22,11 @@ module c_compiler_options
 import c
 import cpp
 private import annotation
+private import platform
 
 redef class ToolContext
-       var cflags_phase: Phase = new CCompilerOptionsPhase(self, null)
+       # Phase to find `cflags`, `ldflags` and `cppflags`
+       var cflags_phase: Phase = new CCompilerOptionsPhase(self, [platform_phase])
 end
 
 private class CCompilerOptionsPhase
@@ -128,35 +130,45 @@ private class CCompilerOptionsPhase
                        end
                end
 
-               # retreive module
+               # Retrieve module
                var mmodule = nmoduledecl.parent.as(AModule).mmodule.as(not null)
 
+               # Get target platform from annotation on annotation
+               var platform = ""
+
+               ## Is there an imported platform?
+               var target_platform = mmodule.target_platform
+               if target_platform != null then
+                       platform = target_platform.name or else ""
+               end
+
+               ## Is the platform declared explicitly?
+               var annots = nat.n_annotations
+               if annots != null then
+                       var items = annots.n_items
+                       if items.length > 1 then
+                               modelbuilder.error(annots, "Annotation error: `annotation_name` accepts only a single annotation, the platform name")
+                               return
+                       end
+                       assert items.length == 1
+
+                       var item = items.first
+                       platform = item.name
+               end
+
+               # Store the flags in the module
                for opt in simplified_options do
-                       var cmd = opt.option
+                       var arg = opt.option
                        if annotation_name == compiler_annotation_name then
-                               process_c_compiler_annotation(mmodule, cmd)
+                               mmodule.cflags.add_one(platform, arg)
                        else if annotation_name == linker_annotation_name then
-                               process_c_linker_annotation(mmodule, cmd)
+                               mmodule.ldflags.add_one(platform, arg)
                        else if annotation_name == cpp_compiler_annotation_name then
-                               process_cpp_compiler_annotation(mmodule, cmd)
+                               mmodule.cppflags.add_one(platform, arg)
                        else abort
                end
        end
 
-       fun process_c_compiler_annotation(mmodule: MModule, opt: String)
-       do
-               mmodule.cflags = "{mmodule.cflags} {opt}"
-       end
-
-       fun process_c_linker_annotation(mmodule: MModule, opt: String)
-       do
-               mmodule.ldflags = "{mmodule.ldflags} {opt}"
-       end
-
-       fun process_cpp_compiler_annotation(mmodule: MModule, opt: String)
-       do
-               mmodule.cppflags = "{mmodule.cppflags} {opt}"
-       end
 end
 
 abstract class CCompilerOption
index e114cd2..ba6c2e0 100644 (file)
@@ -27,7 +27,8 @@ end
 redef class MModule
        private var cpp_file: nullable CPPCompilationUnit = null
 
-       var cppflags = "" is writable
+       # Custom options for the C++ compiler (CPPFLAGS)
+       var cppflags = new MultiHashMap[String, String]
 end
 
 class CPPLanguage
@@ -133,7 +134,7 @@ class CPPLanguage
                mmodule.ffi_files.add(file)
 
                # add linked option to support C++
-               mmodule.ldflags = "{mmodule.ldflags} -lstdc++"
+               mmodule.ldflags.add_one("", "-lstdc++")
        end
 
        redef fun compile_callback(callback, mmodule, mainmodule, ecc)
@@ -180,7 +181,7 @@ class ExternCppFile
        var mmodule: MModule
 
        redef fun makefile_rule_name do return "{filename.basename("")}.o"
-       redef fun makefile_rule_content do return "$(CXX) $(CFLAGS) {mmodule.cppflags} -c {filename.basename("")} -o {filename.basename("")}.o"
+       redef fun makefile_rule_content do return "$(CXX) $(CFLAGS) {mmodule.cppflags[""].join(" ")} -c {filename.basename("")} -o {filename.basename("")}.o"
        redef fun compiles_to_o_file do return true
 end
 
index cccb7a0..93acf66 100644 (file)
@@ -60,6 +60,8 @@ redef class MModule
                        if mod.uses_ffi then ffi_ccu.header_custom.add("#include \"{mod.c_name}._ffi.h\"\n")
                end
 
+               var cflags = self.cflags[""].join(" ")
+
                ffi_ccu.write_as_impl(self, compdir)
                for filename in ffi_ccu.files do
                        var f = new ExternCFile(filename, cflags)
index 77c3c56..7827dac 100644 (file)
@@ -242,8 +242,8 @@ redef class MModule
        # Tell the C compiler where to find jni.h and how to link with libjvm
        private fun insert_compiler_options
        do
-               cflags = "{cflags} -I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/"
-               ldflags = "{ldflags} -L $(JNI_LIB_PATH) -ljvm"
+               cflags.add_one("", "-I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/")
+               ldflags.add_one("", "-L $(JNI_LIB_PATH) -ljvm")
        end
 
        # Name of the generated Java class where to store all implementation methods of this module
index 7e309bc..4aafb91 100644 (file)
@@ -154,7 +154,7 @@ private class ObjCCompilationUnit
 
                files.add compdir/c_file
 
-               mmodule.ldflags = "{mmodule.ldflags} -lobjc"
+               mmodule.ldflags.add_one("", "-lobjc")
 
                return new ExternObjCFile(compdir/c_file, mmodule)
        end
index ffd90bc..f4b04a6 100644 (file)
@@ -34,6 +34,8 @@ end
 class AndroidPlatform
        super Platform
 
+       redef fun name do return "android"
+
        redef fun supports_libgc do return true
 
        redef fun supports_libunwind do return false
@@ -138,12 +140,21 @@ class AndroidToolchain
                        end
                end
 
-               ## Generate delagating makefile
+               ## Generate delegating makefile
                dir = "{android_project_root}/jni/"
                """
 include $(call all-subdir-makefiles)
                """.write_to_file("{dir}/Android.mk")
 
+               # Gather ldflags for Android
+               var ldflags = new Array[String]
+               var platform_name = "android"
+               for mmodule in compiler.mainmodule.in_importation.greaters do
+                       if mmodule.ldflags.keys.has(platform_name) then
+                               ldflags.add_all mmodule.ldflags[platform_name]
+                       end
+               end
+
                ### generate makefile into "{compile_dir}/Android.mk"
                dir = compile_dir
                """
@@ -154,7 +165,7 @@ LOCAL_CFLAGS        := -D ANDROID -D WITH_LIBGC
 LOCAL_MODULE    := main
 LOCAL_SRC_FILES := \\
 {{{cfiles.join(" \\\n")}}}
-LOCAL_LDLIBS    := -llog -landroid -lEGL -lGLESv1_CM -lz libgc.a
+LOCAL_LDLIBS    := {{{ldflags.join(" ")}}} libgc.a
 LOCAL_STATIC_LIBRARIES := android_native_app_glue png
 
 include $(BUILD_SHARED_LIBRARY)
index dc2662f..3e9199a 100644 (file)
@@ -31,6 +31,7 @@ end
 class EmscriptenPlatform
        super Platform
 
+       redef fun name do return "emscripten"
        redef fun supports_libunwind do return false
        redef fun supports_libgc do return false
        redef fun supports_linker_script do return false
index 5b7f7a5..40069c4 100644 (file)
@@ -104,6 +104,10 @@ end
 #
 # Services will be added to this class in other modules.
 class Platform
+
+       # Simple lower-case name of the platform
+       fun name: nullable String do return null
+
        # Does the platform provide and support the library `unwind`?
        fun supports_libunwind: Bool do return true
 
index 9fceaad..d7103db 100644 (file)
@@ -31,6 +31,8 @@ end
 class PnaclPlatform
        super Platform
 
+       redef fun name do return "pnacl"
+
        redef fun supports_libunwind do return false
 
        redef fun no_main do return true