compiler: add and use `MModule::c_name`
[nit.git] / src / compiler / abstract_compiler.nit
index e80e566..16c0e4b 100644 (file)
@@ -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
@@ -232,6 +198,7 @@ class MakefileToolchain
                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"
 
@@ -317,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
@@ -353,18 +320,13 @@ class MakefileToolchain
                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")
@@ -404,6 +366,24 @@ class MakefileToolchain
                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
@@ -474,7 +454,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
@@ -482,11 +462,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
@@ -495,7 +473,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
@@ -513,7 +491,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)
@@ -1035,9 +1013,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
@@ -1054,7 +1031,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
@@ -1062,11 +1039,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
 
@@ -1650,11 +1626,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
@@ -1724,7 +1697,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
@@ -1830,7 +1803,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
@@ -1858,7 +1831,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
@@ -3042,6 +3015,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