diff --git a/src/compiler/crystal/codegen/link.cr b/src/compiler/crystal/codegen/link.cr index dbda33033695..483edc500b35 100644 --- a/src/compiler/crystal/codegen/link.cr +++ b/src/compiler/crystal/codegen/link.cr @@ -104,14 +104,6 @@ module Crystal end class Program - def object_extension - case - when has_flag?("windows") then ".obj" - when has_flag?("wasm32") then ".wasm" - else ".o" - end - end - def lib_flags has_flag?("windows") ? lib_flags_windows : lib_flags_posix end diff --git a/src/compiler/crystal/codegen/target.cr b/src/compiler/crystal/codegen/target.cr index b4f8c2f9f4a3..51881c5a3571 100644 --- a/src/compiler/crystal/codegen/target.cr +++ b/src/compiler/crystal/codegen/target.cr @@ -77,6 +77,21 @@ class Crystal::Codegen::Target end end + def executable_extension + case + when windows? then ".exe" + else "" + end + end + + def object_extension + case + when windows? then ".obj" + when @architecture == "wasm32" then ".wasm" + else ".o" + end + end + def macos? @environment.starts_with?("darwin") || @environment.starts_with?("macos") end diff --git a/src/compiler/crystal/command.cr b/src/compiler/crystal/command.cr index 67b82425fad9..a8b4e43fac77 100644 --- a/src/compiler/crystal/command.cr +++ b/src/compiler/crystal/command.cr @@ -327,14 +327,13 @@ class Crystal::Command compiler : Compiler, sources : Array(Compiler::Source), output_filename : String, - original_output_filename : String, arguments : Array(String), specified_output : Bool, hierarchy_exp : String?, cursor_location : String?, output_format : String? do def compile(output_filename = self.output_filename) - compiler.emit_base_filename = original_output_filename + compiler.emit_base_filename = output_filename.rchop(File.extname(output_filename)) compiler.compile sources, output_filename end @@ -521,17 +520,23 @@ class Crystal::Command if has_stdin_filename sources << Compiler::Source.new(filenames.shift, STDIN.gets_to_end) end - sources += gather_sources(filenames) - first_filename = sources.first.filename - first_file_ext = File.extname(first_filename) - original_output_filename = File.basename(first_filename, first_file_ext) + sources.concat gather_sources(filenames) - # Check if we'll overwrite the main source file - if first_file_ext.empty? && !output_filename && !no_codegen && !run && first_filename == File.expand_path(original_output_filename) - error "compilation will overwrite source file '#{Crystal.relative_filename(first_filename)}', either change its extension to '.cr' or specify an output file with '-o'" + output_extension = compiler.cross_compile? ? compiler.codegen_target.object_extension : compiler.codegen_target.executable_extension + if output_filename + if File.extname(output_filename).empty? + output_filename += output_extension + end + else + first_filename = sources.first.filename + output_filename = "#{::Path[first_filename].stem}#{output_extension}" + + # Check if we'll overwrite the main source file + if !no_codegen && !run && first_filename == File.expand_path(output_filename) + error "compilation will overwrite source file '#{Crystal.relative_filename(first_filename)}', either change its extension to '.cr' or specify an output file with '-o'" + end end - output_filename ||= original_output_filename output_format ||= "text" unless output_format.in?("text", "json") error "You have input an invalid format, only text and JSON are supported" @@ -543,7 +548,7 @@ class Crystal::Command error "can't use `#{output_filename}` as output filename because it's a directory" end - @config = CompilerConfig.new compiler, sources, output_filename, original_output_filename, arguments, specified_output, hierarchy_exp, cursor_location, output_format + @config = CompilerConfig.new compiler, sources, output_filename, arguments, specified_output, hierarchy_exp, cursor_location, output_format end private def gather_sources(filenames) diff --git a/src/compiler/crystal/compiler.cr b/src/compiler/crystal/compiler.cr index 9d8e3b156975..300ea71ae75b 100644 --- a/src/compiler/crystal/compiler.cr +++ b/src/compiler/crystal/compiler.cr @@ -39,7 +39,7 @@ module Crystal # If `true`, doesn't generate an executable but instead # creates a `.o` file and outputs a command line to link # it in the target machine. - property cross_compile = false + property? cross_compile = false # Compiler flags. These will be true when checked in macro # code by the `flag?(...)` macro method. @@ -306,17 +306,16 @@ module Crystal private def cross_compile(program, units, output_filename) unit = units.first llvm_mod = unit.llvm_mod - object_name = output_filename + program.object_extension @progress_tracker.stage("Codegen (bc+obj)") do optimize llvm_mod if @release unit.emit(@emit_targets, emit_base_filename || output_filename) - target_machine.emit_obj_to_file llvm_mod, object_name + target_machine.emit_obj_to_file llvm_mod, output_filename end - _, command, args = linker_command(program, [object_name], output_filename, nil) + _, command, args = linker_command(program, [output_filename], output_filename, nil) print_command(command, args) end @@ -708,7 +707,7 @@ module Crystal @name = "#{@name[0..16]}-#{::Crystal::Digest::MD5.hexdigest(@name)}" end - @object_extension = program.object_extension + @object_extension = compiler.codegen_target.object_extension end def compile diff --git a/src/compiler/crystal/macros/macros.cr b/src/compiler/crystal/macros/macros.cr index c74a482f9d03..b5d1bb281c1a 100644 --- a/src/compiler/crystal/macros/macros.cr +++ b/src/compiler/crystal/macros/macros.cr @@ -127,7 +127,7 @@ class Crystal::Program # When cross-compiling, the host compiler shouldn't copy the config for # the target compiler and use the system defaults instead. # TODO: Add configuration overrides for host compiler to CLI. - unless compiler.cross_compile + unless compiler.cross_compile? host_compiler.flags = compiler.flags host_compiler.dump_ll = compiler.dump_ll? host_compiler.link_flags = compiler.link_flags