# Write the Makefile
fun write_makefile(compile_dir: String, cfiles: Array[String])
do
var mainmodule = compiler.mainmodule
var platform = compiler.target_platform
var outname = outfile(mainmodule)
var real_outpath = compile_dir.relpath(outname)
var outpath = real_outpath.escape_to_mk
if outpath != real_outpath then
# If the name is crazy and need escaping, we will do an indirection
# 1. generate the binary in the nit_compile dir under an escaped name
# 2. copy the binary at the right place in the `all` goal.
outpath = mainmodule.c_name
end
var makename = makefile_name
var makepath = "{compile_dir}/{makename}"
var makefile = new FileWriter.open(makepath)
var linker_options = new HashSet[String]
for m in mainmodule.in_importation.greaters do
var libs = m.collect_linker_libs
if libs != null then linker_options.add_all(libs)
end
var debug = toolcontext.opt_debug.value
makefile.write """
ifeq ($(origin CC), default)
CC = ccache cc
endif
ifeq ($(origin CXX), default)
CXX = ccache c++
endif
CFLAGS ?= -g {{{if not debug then "-O2" else ""}}} -Wno-unused-value -Wno-switch -Wno-attributes -Wno-trigraphs
CINCL =
LDFLAGS ?=
LDLIBS ?= -lm {{{linker_options.join(" ")}}}
\n"""
if self.toolcontext.opt_trace.value then makefile.write "LDLIBS += -llttng-ust -ldl\n"
if toolcontext.opt_shared_lib.value then
makefile.write """
CFLAGS += -fPIC
LDFLAGS += -shared -Wl,-soname,{{{outname}}}
"""
end
makefile.write "\n# SPECIAL CONFIGURATION FLAGS\n"
if platform.supports_libunwind then
if toolcontext.opt_no_stacktrace.value then
makefile.write "NO_STACKTRACE ?= True"
else
makefile.write "NO_STACKTRACE ?= # Set to `True` to enable"
end
end
# Dynamic adaptations
# While `platform` enable complex toolchains, they are statically applied
# For a dynamic adaptsation of the compilation, the generated Makefile should check and adapt things itself
makefile.write "\n\n"
# Check and adapt the targeted system
makefile.write("uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')\n")
# Check and adapt for the compiler used
# clang need an additionnal `-Qunused-arguments`
makefile.write("clang_check := $(shell sh -c '$(CC) -v 2>&1 | grep -q clang; echo $$?')\nifeq ($(clang_check), 0)\n\tCFLAGS += -Qunused-arguments\nendif\n")
if platform.supports_libunwind then
makefile.write """
ifneq ($(NO_STACKTRACE), True)
# Check and include lib-unwind in a portable way
ifneq ($(uname_S),Darwin)
# already included on macosx, but need to get the correct flags in other supported platforms.
ifeq ($(shell pkg-config --exists 'libunwind'; echo $$?), 0)
LDLIBS += `pkg-config --libs libunwind`
CFLAGS += `pkg-config --cflags libunwind`
else
$(warning "[_] stack-traces disabled. Please install libunwind-dev.")
CFLAGS += -D NO_STACKTRACE
endif
endif
else
# Stacktraces disabled
CFLAGS += -D NO_STACKTRACE
endif
"""
else
makefile.write("CFLAGS += -D NO_STACKTRACE\n\n")
end
makefile.write """
# Special configuration for Darwin
ifeq ($(uname_S),Darwin)
# Remove POSIX flag -lrt
LDLIBS := $(filter-out -lrt,$(LDLIBS))
endif
# Special configuration for Windows under mingw64
ifneq ($(findstring MINGW64,$(uname_S)),)
# Use the pcreposix regex library
LDLIBS += -lpcreposix
# Remove POSIX flag -lrt
LDLIBS := $(filter-out -lrt,$(LDLIBS))
# Silence warnings when storing Int, Char and Bool as pointer address
CFLAGS += -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast
endif
# Add the compilation dir to the Java CLASSPATH
ifeq ($(CLASSPATH),)
CLASSPATH := .
else
CLASSPATH := $(CLASSPATH):.
endif
"""
makefile.write("all: {outpath}\n")
if outpath != real_outpath then
makefile.write("\tcp -- {outpath.escape_to_sh} {real_outpath.escape_to_sh.replace("$","$$")}")
end
makefile.write("\n")
var ofiles = new Array[String]
var dep_rules = new Array[String]
# Compile each generated file
for f in cfiles do
var o = f.strip_extension(".c") + ".o"
makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) $(CINCL) -c -o {o} {f}\n\n")
ofiles.add(o)
dep_rules.add(o)
end
# Generate linker script, if any
if not compiler.linker_script.is_empty then
var linker_script_path = "{compile_dir}/linker_script"
ofiles.add "linker_script"
var f = new FileWriter.open(linker_script_path)
for l in compiler.linker_script do
f.write l
f.write "\n"
end
f.close
end
# pkg-config annotation support
var pkgconfigs = new Array[String]
for f in compiler.extern_bodies do
pkgconfigs.add_all f.pkgconfigs
end
# Only test if pkg-config is used
if not pkgconfigs.is_empty then
# Check availability of pkg-config, silence the proc output
toolcontext.check_pkgconfig_packages pkgconfigs
# Double the check in the Makefile in case it's distributed
makefile.write """
# does pkg-config exists?
ifneq ($(shell which pkg-config >/dev/null; echo $$?), 0)
$(error "Command `pkg-config` not found. Please install it")
endif
"""
for p in pkgconfigs do
makefile.write """
# Check for library {{{p}}}
ifneq ($(shell pkg-config --exists '{{{p}}}'; echo $$?), 0)
$(error "pkg-config: package {{{p}}} is not found.")
endif
"""
end
end
# Compile each required extern body into a specific .o
var java_files = new Array[ExternFile]
for f in compiler.extern_bodies do
var o = f.makefile_rule_name
makefile.write("{o}: {f.filename}\n")
makefile.write("\t{f.makefile_rule_content}\n\n")
dep_rules.add(f.makefile_rule_name)
if f.compiles_to_o_file then ofiles.add(o)
if f.add_to_jar then java_files.add(f)
end
if not java_files.is_empty then
var jar_file = "{outpath}.jar"
var class_files_array = new Array[String]
for f in java_files do class_files_array.add(f.makefile_rule_name)
var class_files = class_files_array.join(" ")
makefile.write("{jar_file}: {class_files}\n")
makefile.write("\tjar cf {jar_file} {class_files}\n\n")
dep_rules.add jar_file
end
# Link edition
var pkg = ""
if not pkgconfigs.is_empty then
pkg = "`pkg-config --libs {pkgconfigs.join(" ")}`"
end
makefile.write("{outpath}: {dep_rules.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outpath.escape_to_sh} {ofiles.join(" ")} $(LDLIBS) {pkg}\n\n")
# Clean
makefile.write("clean:\n\trm -f {ofiles.join(" ")} 2>/dev/null\n")
if outpath != real_outpath then
makefile.write("\trm -f -- {outpath.escape_to_sh} 2>/dev/null\n")
end
makefile.close
self.toolcontext.info("Generated makefile: {makepath}", 2)
makepath.file_copy_to "{compile_dir}/Makefile"
end
src/compiler/abstract_compiler.nit:355,2--573,4
redef fun write_makefile(compile_dir, cfiles)
do
# Do nothing, already done in `write_files`
end
src/platform/android.nit:473,2--476,4
redef fun write_makefile(compile_dir, cfiles)
do
super
var emcc_make_flags = "CC=emcc CXX=em++ CFLAGS='-Wno-unused-value -Wno-switch -Qunused-arguments -s ALLOW_MEMORY_GROWTH=1"
var release = toolcontext.opt_release.value
if release then
emcc_make_flags += "' LDFLAGS='--minify 1'"
else emcc_make_flags += " -g'"
var make_flags = self.toolcontext.opt_make_flags.value or else ""
make_flags += emcc_make_flags
self.toolcontext.opt_make_flags.value = make_flags
end
src/platform/emscripten.nit:48,2--62,4
redef fun write_makefile(compile_dir, cfiles)
do
var project_name = app_project.short_name
# ---
# project_folder (source code)
# Create the plist in the same directory as the generated C code
if not compile_dir.file_exists then compile_dir.mkdir
var plist = new PlistTemplate(app_project.name, app_project.namespace,
app_project.version, app_project.version_code.to_s)
plist.write_to_file compile_dir/"Info.plist"
# Copy the folder `ios/AppIcon.appiconset` from the root of the project
var project_root = "."
var mpackage = compiler.mainmodule.first_real_mmodule.mpackage
if mpackage != null then
var root = mpackage.root
if root != null then
var filepath = root.filepath
if filepath != null then
project_root = filepath
end
end
end
# Copy all resources
var app_files = [project_root]
app_files.add_all app_project.files
var icons_found = false
# Prepare the `Assets.xcassets` folder
var target_assets_dir = compile_dir / "Assets.xcassets"
if not target_assets_dir.file_exists then target_assets_dir.mkdir
"""
{
"info" : {
"version" : 1,
"author" : "nitc"
}
}""".write_to_file target_assets_dir / "Contents.json"
(compile_dir / "assets").mkdir
for path in app_files do
# Icon
var icon_dir = path / "ios" / "AppIcon.appiconset"
if icon_dir.file_exists then
icons_found = true
# copy the res folder to the compile dir
icon_dir = icon_dir.realpath
toolcontext.exec_and_check(["cp", "-R", icon_dir, target_assets_dir], "iOS project error")
end
# Assets
var assets_dir = path / "assets"
if assets_dir.file_exists then
assets_dir = assets_dir.realpath
toolcontext.exec_and_check(["cp", "-r", assets_dir, compile_dir], "iOS project error")
end
end
# ---
# project_folder.xcodeproj (projet meta data)
# Create an XCode project directory
var dir = ios_project_root/project_name+".xcodeproj"
if not dir.file_exists then dir.mkdir
# Create a PBX project file
var pbx = new PbxprojectTemplate(project_name)
## Register all source files
for file in cfiles do pbx.add_file new PbxFile(file)
for file in compiler.extern_bodies do
pbx.add_file new PbxFile(file.filename.basename)
end
# GC
if compiler.target_platform.supports_libgc then
var bdwgc_dir = bdwgc_dir
assert bdwgc_dir != null
pbx.cflags = "-I '{bdwgc_dir}/include/' -I '{bdwgc_dir}/libatomic_ops/src' -fno-strict-aliasing " +
"-DWITH_LIBGC -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS -DGC_NO_THREADS_DISCOVERY -DNO_DYLD_BIND_FULLY_IMAGE " +
"-DGC_DISABLE_INCREMENTAL -DGC_THREADS -DUSE_MMAP -DUSE_MUNMAP -DGC_GCJ_SUPPORT -DJAVA_FINALIZATION "
var gc_file = new PbxFile("{bdwgc_dir}/extra/gc.c")
gc_file.cflags = "-Wno-tautological-pointer-compare"
pbx.add_file gc_file
end
# Basic storyboard, mainly to have the right screen size
var launch_screen_storyboard = new LaunchScreenStoryboardTemplate
launch_screen_storyboard.title = app_project.name
launch_screen_storyboard.subtitle = "app.nit"
launch_screen_storyboard.write_to_file ios_project_root / "LaunchScreen.storyboard"
# Register the Assets.xcassets folder in the project description
if icons_found then
var xcassets = new PbxFile("Assets.xcassets")
pbx.add_file xcassets
end
pbx.write_to_file dir / "project.pbxproj"
end
src/platform/ios.nit:88,2--197,4