From: Jean Privat Date: Thu, 29 Jan 2015 11:59:01 +0000 (+0700) Subject: Merge: ldflags for Android X-Git-Tag: v0.7.1~3 X-Git-Url: http://nitlanguage.org?hp=fac640cbcd6ed13bce5bbf96f59fa8bebe19530a Merge: ldflags for Android 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 Reviewed-by: Jean Privat Reviewed-by: Alexandre Terrasa --- diff --git a/lib/android/aware.nit b/lib/android/aware.nit new file mode 100644 index 0000000..92a3a80 --- /dev/null +++ b/lib/android/aware.nit @@ -0,0 +1,20 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2014 Alexis Laferrière +# +# 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) diff --git a/lib/android/log.nit b/lib/android/log.nit index 30beb62..c165331 100644 --- a/lib/android/log.nit +++ b/lib/android/log.nit @@ -15,7 +15,7 @@ # limitations under the License. # Advanced Android logging services -module log +module log is ldflags "-llog" import platform diff --git a/lib/android/native_app_glue.nit b/lib/android/native_app_glue.nit index af3c797..4ae4753 100644 --- a/lib/android/native_app_glue.nit +++ b/lib/android/native_app_glue.nit @@ -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 diff --git a/lib/android/platform.nit b/lib/android/platform.nit index fca03e0..7c15af5 100644 --- a/lib/android/platform.nit +++ b/lib/android/platform.nit @@ -27,3 +27,4 @@ end import java import app +import aware diff --git a/lib/egl.nit b/lib/egl.nit index 4c24b57..b664c8a 100644 --- a/lib/egl.nit +++ b/lib/egl.nit @@ -21,7 +21,12 @@ # 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 diff --git a/lib/glesv2/glesv2.nit b/lib/glesv2/glesv2.nit index 06803ae..ca7faf1 100644 --- a/lib/glesv2/glesv2.nit +++ b/lib/glesv2/glesv2.nit @@ -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 diff --git a/lib/mnit_android/android_assets.nit b/lib/mnit_android/android_assets.nit index 2c703bb..8f61c90 100644 --- a/lib/mnit_android/android_assets.nit +++ b/lib/mnit_android/android_assets.nit @@ -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 diff --git a/lib/mnit_android/android_opengles1.nit b/lib/mnit_android/android_opengles1.nit index 5996214..5ff9e7c 100644 --- a/lib/mnit_android/android_opengles1.nit +++ b/lib/mnit_android/android_opengles1.nit @@ -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 diff --git a/src/c_tools.nit b/src/c_tools.nit index b835f2a..6fa1f05 100644 --- a/src/c_tools.nit +++ b/src/c_tools.nit @@ -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 diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index dfe463c..b1a5879 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -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 diff --git a/src/compiler/compiler_ffi.nit b/src/compiler/compiler_ffi.nit index ac7bad3..dea917b 100644 --- a/src/compiler/compiler_ffi.nit +++ b/src/compiler/compiler_ffi.nit @@ -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] diff --git a/src/ffi/c.nit b/src/ffi/c.nit index 1790f48..495d4e6 100644 --- a/src/ffi/c.nit +++ b/src/ffi/c.nit @@ -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 diff --git a/src/ffi/c_compiler_options.nit b/src/ffi/c_compiler_options.nit index e4756a8..4fbd5c4 100644 --- a/src/ffi/c_compiler_options.nit +++ b/src/ffi/c_compiler_options.nit @@ -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 diff --git a/src/ffi/cpp.nit b/src/ffi/cpp.nit index e114cd2..ba6c2e0 100644 --- a/src/ffi/cpp.nit +++ b/src/ffi/cpp.nit @@ -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 diff --git a/src/ffi/ffi.nit b/src/ffi/ffi.nit index cccb7a0..93acf66 100644 --- a/src/ffi/ffi.nit +++ b/src/ffi/ffi.nit @@ -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) diff --git a/src/ffi/java.nit b/src/ffi/java.nit index 77c3c56..7827dac 100644 --- a/src/ffi/java.nit +++ b/src/ffi/java.nit @@ -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 diff --git a/src/ffi/objc.nit b/src/ffi/objc.nit index 7e309bc..4aafb91 100644 --- a/src/ffi/objc.nit +++ b/src/ffi/objc.nit @@ -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 diff --git a/src/platform/android.nit b/src/platform/android.nit index ffd90bc..f4b04a6 100644 --- a/src/platform/android.nit +++ b/src/platform/android.nit @@ -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) diff --git a/src/platform/emscripten.nit b/src/platform/emscripten.nit index dc2662f..3e9199a 100644 --- a/src/platform/emscripten.nit +++ b/src/platform/emscripten.nit @@ -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 diff --git a/src/platform/platform.nit b/src/platform/platform.nit index 5b7f7a5..40069c4 100644 --- a/src/platform/platform.nit +++ b/src/platform/platform.nit @@ -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 diff --git a/src/platform/pnacl.nit b/src/platform/pnacl.nit index 9fceaad..d7103db 100644 --- a/src/platform/pnacl.nit +++ b/src/platform/pnacl.nit @@ -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