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 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)
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 =\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n")
+ makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch -Wno-attributes\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")
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]
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} {ofiles.join(" ")} $(LDLIBS) {pkg}\n\n")
+ 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)
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)
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")
var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
self.mainmodule.linearize_mclassdefs(cds)
for cd in cds do
- if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
- var n = self.modelbuilder.mclassdef2nclassdef[cd]
- for npropdef in n.n_propdefs do
- if npropdef isa AAttrPropdef then
- npropdef.init_expr(v, recv)
- end
+ for npropdef in modelbuilder.collect_attr_propdef(cd) do
+ npropdef.init_expr(v, recv)
end
end
end
var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
self.mainmodule.linearize_mclassdefs(cds)
for cd in cds do
- if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
- var n = self.modelbuilder.mclassdef2nclassdef[cd]
- for npropdef in n.n_propdefs do
- if npropdef isa AAttrPropdef then
- npropdef.check_expr(v, recv)
- end
+ for npropdef in modelbuilder.collect_attr_propdef(cd) do
+ npropdef.check_expr(v, recv)
end
end
end
# (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
do
if is_abstract then return true
var modelbuilder = v.compiler.modelbuilder
- if modelbuilder.mpropdef2npropdef.has_key(self) then
- var npropdef = modelbuilder.mpropdef2npropdef[self]
- return npropdef.can_inline
- else if self.mproperty.is_root_init then
+ var node = modelbuilder.mpropdef2node(self)
+ if node isa APropdef then
+ return node.can_inline
+ else if node isa AClassdef then
# Automatic free init is always inlined since it is empty or contains only attribtes assigments
return true
else
do
var modelbuilder = v.compiler.modelbuilder
var val = constant_value
- if modelbuilder.mpropdef2npropdef.has_key(self) then
- var npropdef = modelbuilder.mpropdef2npropdef[self]
+ var node = modelbuilder.mpropdef2node(self)
+ if node isa APropdef then
var oldnode = v.current_node
- v.current_node = npropdef
+ v.current_node = node
self.compile_parameter_check(v, arguments)
- npropdef.compile_to_c(v, self, arguments)
+ node.compile_to_c(v, self, arguments)
v.current_node = oldnode
- else if self.mproperty.is_root_init then
- var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
+ else if node isa AClassdef then
var oldnode = v.current_node
- v.current_node = nclassdef
+ v.current_node = node
self.compile_parameter_check(v, arguments)
- nclassdef.compile_to_c(v, self, arguments)
+ node.compile_to_c(v, self, arguments)
v.current_node = oldnode
else if val != null then
v.ret(v.value_instance(val))
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
# Create a tool context to handle options and paths
var toolcontext = new ToolContext
-toolcontext.tooldescription = "Usage: nitg [OPTION]... file.nit...\nCompiles Nit programs."
+toolcontext.tooldescription = "Usage: nitc [OPTION]... file.nit...\nCompiles Nit programs."
# We do not add other options, so process them now!
toolcontext.process_options(args)