X-Git-Url: http://nitlanguage.org?ds=sidebyside diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index e3c2fdf..abfbf3f 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -34,8 +34,6 @@ redef class ToolContext 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 @@ -81,6 +79,8 @@ redef class ToolContext 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) @@ -151,43 +151,9 @@ end 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 @@ -225,12 +191,14 @@ class MakefileToolchain do var platform = compiler.mainmodule.target_platform if self.toolcontext.opt_stacktrace.value == "nitstack" and (platform == null or platform.supports_libunwind) then compiler.build_c_to_nit_bindings - var cc_opt_with_libgc = "-DWITH_LIBGC `pkg-config --cflags bdw-gc`" + var cc_opt_with_libgc = "-DWITH_LIBGC" if platform != null and not platform.supports_libgc then cc_opt_with_libgc = "" # Add gc_choser.h to aditionnal bodies 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" @@ -316,7 +284,7 @@ class MakefileToolchain 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 @@ -347,23 +315,25 @@ class MakefileToolchain var outname = outfile(mainmodule) - var outpath = compile_dir.relpath(outname) + 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(mainmodule) 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 `pkg-config --libs bdw-gc` {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") @@ -385,7 +355,11 @@ class MakefileToolchain makefile.write("ifdef NEED_LIBUNWIND\n\tLDLIBS += -lunwind\nendif\n") - makefile.write("all: {outpath}\n\n") + 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] @@ -399,6 +373,28 @@ class MakefileToolchain var java_files = new Array[ExternFile] + var pkgconfigs = new Array[String] + 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 @@ -424,9 +420,16 @@ class MakefileToolchain end # Link edition - makefile.write("{outpath}: {dep_rules.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outpath} {ofiles.join(" ")} $(LDLIBS)\n\n") + 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 {ofiles.join(" ")} 2>/dev/null\n\n") + makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n") + if outpath != real_outpath then + makefile.write("\trm -- {outpath.escape_to_sh} 2>/dev/null\n") + end makefile.close self.toolcontext.info("Generated makefile: {makepath}", 2) @@ -465,7 +468,7 @@ abstract class AbstractCompiler 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 @@ -473,11 +476,9 @@ abstract class AbstractCompiler # 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 @@ -486,7 +487,7 @@ abstract class AbstractCompiler 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 @@ -504,7 +505,7 @@ abstract class AbstractCompiler 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) @@ -537,9 +538,9 @@ abstract class AbstractCompiler stream.write("static const C_Nit_Names map[{names.length}] = \{\n") for i in names.keys do stream.write("\{\"") - stream.write(i) + stream.write(i.escape_to_c) stream.write("\",\"") - stream.write(names[i]) + stream.write(names[i].escape_to_c) stream.write("\"\},\n") end stream.write("\};\n") @@ -1026,9 +1027,8 @@ class CodeWriter # (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 @@ -1045,7 +1045,7 @@ abstract class AbstractCompilerVisitor 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 @@ -1053,11 +1053,10 @@ abstract class AbstractCompilerVisitor # 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 @@ -1641,11 +1640,8 @@ class RuntimeVariable # 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 @@ -1715,7 +1711,7 @@ redef class MClassType 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 @@ -1821,7 +1817,7 @@ redef class MClass 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 @@ -1849,7 +1845,7 @@ redef class MPropDef 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 @@ -3033,6 +3029,19 @@ redef class Array[E] 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