diff --git a/spec/compiler/codegen/fun_spec.cr b/spec/compiler/codegen/fun_spec.cr new file mode 100644 index 000000000000..ad1dd70e553f --- /dev/null +++ b/spec/compiler/codegen/fun_spec.cr @@ -0,0 +1,21 @@ +require "../../spec_helper" + +describe "Codegen: fun" do + it "sets external linkage by default" do + mod = codegen(<<-CRYSTAL, inject_primitives: false, single_module: false) + fun foo; end + fun __crystal_foo; end + CRYSTAL + mod.functions["foo"].linkage.should eq(LLVM::Linkage::External) + mod.functions["__crystal_foo"].linkage.should eq(LLVM::Linkage::External) + end + + it "sets internal linkage to __crystal_ funs when compiling to single module" do + mod = codegen(<<-CRYSTAL, inject_primitives: false, single_module: true) + fun foo; end + fun __crystal_foo; end + CRYSTAL + mod.functions["foo"].linkage.should eq(LLVM::Linkage::External) + mod.functions["__crystal_foo"].linkage.should eq(LLVM::Linkage::Internal) + end +end diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 4758ddc74253..0f7f1b124b2c 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -221,9 +221,9 @@ def prepare_macro_call(macro_body, flags = nil, &) {program, a_macro, call} end -def codegen(code, inject_primitives = true, debug = Crystal::Debug::None, filename = __FILE__) +def codegen(code, *, inject_primitives = true, single_module = false, debug = Crystal::Debug::None, filename = __FILE__) result = semantic code, inject_primitives: inject_primitives, filename: filename - result.program.codegen(result.node, single_module: false, debug: debug)[""].mod + result.program.codegen(result.node, single_module: single_module, debug: debug)[""].mod end private def new_program diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr index 7e15b1bdc385..e4d05ba4aaae 100644 --- a/src/compiler/crystal/codegen/codegen.cr +++ b/src/compiler/crystal/codegen/codegen.cr @@ -283,6 +283,7 @@ module Crystal ret_type = @llvm_typer.llvm_return_type(@main_ret_type) main_type = LLVM::Type.function([llvm_context.int32, llvm_context.void_pointer.pointer], ret_type) @main = @llvm_mod.functions.add(MAIN_NAME, main_type) + @main.linkage = LLVM::Linkage::Internal if @single_module @fun_types = { {@llvm_mod, MAIN_NAME} => main_type } if @program.has_flag?("msvc") diff --git a/src/compiler/crystal/codegen/fun.cr b/src/compiler/crystal/codegen/fun.cr index abe57df37aac..de6a9e32a233 100644 --- a/src/compiler/crystal/codegen/fun.cr +++ b/src/compiler/crystal/codegen/fun.cr @@ -395,6 +395,14 @@ class Crystal::CodeGenVisitor context.fun.call_convention = call_convention end + if @single_module && mangled_name.starts_with?("__crystal_") + # FIXME: macos ld fails to link when the personality fun is internal; it + # might work with lld so we might want to check the linker? + unless @program.has_flag?("darwin") && mangled_name.starts_with?("__crystal_personality") + context.fun.linkage = LLVM::Linkage::Internal + end + end + i = 0 args.each do |arg| param = context.fun.params[i + offset]