var opt_no_cc = new OptionBool("Do not invoke C compiler", "--no-cc")
# --no-main
var opt_no_main = new OptionBool("Do not generate main entry point", "--no-main")
- # --cc-paths
- var opt_cc_path = new OptionArray("Set include path for C header files (may be used more than once)", "--cc-path")
# --make-flags
var opt_make_flags = new OptionString("Additional options to make", "--make-flags")
# --max-c-lines
self.option_context.add_option(self.opt_no_gcc_directive)
self.option_context.add_option(self.opt_release)
self.option_context.add_option(self.opt_max_c_lines, self.opt_group_c_files)
+
+ opt_no_main.hidden = true
end
redef fun process_options(args)
class MakefileToolchain
super Toolchain
- # The list of directories to search for included C headers (-I for C compilers)
- # The list is initially set with :
- # * the toolcontext --cc-path option
- # * the NIT_CC_PATH environment variable
- # * `toolcontext.nit_dir`
- # Path can be added (or removed) by the client
- var cc_paths = new Array[String]
-
- # The clib directory of Nit
- # Used to found some common runtime
- var clib: String is noinit
-
- protected fun gather_cc_paths
- do
- # Look for the the Nit clib path
- var path_env = toolcontext.nit_dir
- if path_env != null then
- var libname = "{path_env}/clib"
- if not libname.file_exists then
- toolcontext.fatal_error(null, "Cannot determine the nit clib path. define envvar NIT_DIR.")
- end
- clib = libname
- end
-
- # Add user defined cc_paths
- cc_paths.append(toolcontext.opt_cc_path.value)
-
- path_env = "NIT_CC_PATH".environ
- if not path_env.is_empty then
- cc_paths.append(path_env.split_with(':'))
- end
- end
redef fun write_and_make(compiler)
do
- gather_cc_paths
-
var compile_dir = compile_dir
# Generate the .h and .c files
var gc_chooser = new ExternCFile("gc_chooser.c", cc_opt_with_libgc)
if cc_opt_with_libgc != "" then gc_chooser.pkgconfigs.add "bdw-gc"
compiler.extern_bodies.add(gc_chooser)
+ var clib = toolcontext.nit_dir / "clib"
compiler.files_to_copy.add "{clib}/gc_chooser.c"
compiler.files_to_copy.add "{clib}/gc_chooser.h"
self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
end
- fun makefile_name(mainmodule: MModule): String do return "{mainmodule.name}.mk"
+ fun makefile_name(mainmodule: MModule): String do return "{mainmodule.c_name}.mk"
fun default_outname(mainmodule: MModule): String
do
var makepath = "{compile_dir}/{makename}"
var makefile = new OFStream.open(makepath)
- var cc_includes = ""
- for p in cc_paths do
- cc_includes += " -I \"" + p + "\""
- end
-
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
- makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n")
+ makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch\nCINCL =\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n")
var ost = toolcontext.opt_stacktrace.value
if (ost == "libunwind" or ost == "nitstack") and (platform == null or platform.supports_libunwind) then makefile.write("NEED_LIBUNWIND := YesPlease\n")
for f in compiler.extern_bodies do
pkgconfigs.add_all f.pkgconfigs
end
+ # Protect pkg-config
+ if not pkgconfigs.is_empty then
+ 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
for f in compiler.extern_bodies do
var o = f.makefile_rule_name
var mainmodule: MModule is writable
# The real main module of the program
- var realmainmodule: MModule
+ var realmainmodule: MModule is noinit
# The modelbuilder used to know the model and the AST
var modelbuilder: ModelBuilder is protected writable
# Is hardening asked? (see --hardening)
fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
- init(mainmodule: MModule, modelbuilder: ModelBuilder)
+ init
do
- self.mainmodule = mainmodule
self.realmainmodule = mainmodule
- self.modelbuilder = modelbuilder
end
# Force the creation of a new file
do
if modelbuilder.toolcontext.opt_group_c_files.value then
if self.files.is_empty then
- var f = new CodeFile(mainmodule.name)
+ var f = new CodeFile(mainmodule.c_name)
self.files.add(f)
end
return self.files.first
fun new_visitor: VISITOR is abstract
# Where global declaration are stored (the main .h)
- var header: CodeWriter is writable
+ var header: CodeWriter is writable, noinit
# Provide a declaration that can be requested (before or latter) by a visitor
fun provide_declaration(key: String, s: String)
# (used for local or global declaration)
fun add_decl(s: String) do self.decl_lines.add(s)
- init(file: CodeFile)
+ init
do
- self.file = file
file.writers.add(self)
end
end
var current_node: nullable ANode = null is writable
# The current `Frame`
- var frame: nullable Frame is writable
+ var frame: nullable Frame = null is writable
# Alias for self.compiler.mainmodule.object_type
fun object_type: MClassType do return self.compiler.mainmodule.object_type
# Alias for self.compiler.mainmodule.bool_type
fun bool_type: MClassType do return self.compiler.mainmodule.bool_type
- var writer: CodeWriter
+ var writer: CodeWriter is noinit
- init(compiler: COMPILER)
+ init
do
- self.compiler = compiler
self.writer = new CodeWriter(compiler.files.last)
end
# false (usual value) means that the variable is a mcasttype or a subtype.
var is_exact: Bool = false is writable
- init(name: String, mtype: MType, mcasttype: MType)
+ init
do
- self.name = name
- self.mtype = mtype
- self.mcasttype = mcasttype
assert not mtype.need_anchor
assert not mcasttype.need_anchor
end
do
var res = self.c_name_cache
if res != null then return res
- res = "{mclass.intro_mmodule.name.to_cmangle}__{mclass.name.to_cmangle}"
+ res = "{mclass.intro_mmodule.c_name}__{mclass.name.to_cmangle}"
self.c_name_cache = res
return res
end
fun c_name: String do
var res = self.c_name_cache
if res != null then return res
- res = "{intro_mmodule.name.to_cmangle}__{name.to_cmangle}"
+ res = "{intro_mmodule.c_name}__{name.to_cmangle}"
self.c_name_cache = res
return res
end
do
var res = self.c_name_cache
if res != null then return res
- res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
+ res = "{self.mclassdef.mmodule.c_name}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
self.c_name_cache = res
return res
end
end
redef class MModule
+ # Return the name of the global C identifier associated to `self`.
+ # This name is used to prefix files and other C identifiers associated with `self`.
+ var c_name: String is lazy do
+ var g = mgroup
+ var res
+ if g != null and g.mproject.name != name then
+ res = g.mproject.name.to_cmangle + "__" + name.to_cmangle
+ else
+ res = name.to_cmangle
+ end
+ return res
+ end
+
# All `MProperty` associated to all `MClassDef` of `mclass`
fun properties(mclass: MClass): Set[MProperty] do
if not self.properties_cache.has_key(mclass) then