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>
--- /dev/null
+# 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)
# limitations under the License.
# Advanced Android logging services
-module log
+module log is ldflags "-llog"
import platform
# 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
import java
import app
+import aware
# 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>
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>
# * 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
# 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
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
# 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
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
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]
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
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
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
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
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)
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
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)
# 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
files.add compdir/c_file
- mmodule.ldflags = "{mmodule.ldflags} -lobjc"
+ mmodule.ldflags.add_one("", "-lobjc")
return new ExternObjCFile(compdir/c_file, mmodule)
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
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
"""
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)
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
#
# 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
class PnaclPlatform
super Platform
+ redef fun name do return "pnacl"
+
redef fun supports_libunwind do return false
redef fun no_main do return true