diff --git a/doc/man/crystal-build.adoc b/doc/man/crystal-build.adoc index b75c8e84a11b..092e84b484c9 100644 --- a/doc/man/crystal-build.adoc +++ b/doc/man/crystal-build.adoc @@ -68,7 +68,8 @@ pass a --code-model flag to LLVM. Disable colored output. *--no-codegen*:: Don't do code generation, just parse the file. -*-o* _FILE_, *--output* _FILE_:: Specify filename of output. +*-o* _FILE_, *--output* _FILE_:: +Specify output path. If a directory, the filename is derived from the first source file (default: current directory) *--prelude*:: Specify prelude to use. The default one initializes the garbage collector. You can also use --prelude=empty to use no preludes. diff --git a/man/crystal.1 b/man/crystal.1 index c39775479e1e..0491235dc479 100644 --- a/man/crystal.1 +++ b/man/crystal.1 @@ -835,4 +835,4 @@ is handy when using Crystal in build setups, for example \*(AqCRYSTAL_OPTS=\-\-d The official web site. .sp .URL "https://github.com/crystal\-lang/crystal" "" "" -Official Repository. \ No newline at end of file +Official Repository. diff --git a/src/compiler/crystal/command.cr b/src/compiler/crystal/command.cr index 3c76bd89935f..93cb3ecb0c38 100644 --- a/src/compiler/crystal/command.cr +++ b/src/compiler/crystal/command.cr @@ -508,7 +508,7 @@ class Crystal::Command opts.on("--no-codegen", "Don't do code generation") do compiler.no_codegen = true end - opts.on("-o FILE", "--output FILE", "Output filename") do |an_output_filename| + opts.on("-o FILE", "--output FILE", "Output path. If a directory, the filename is derived from the first source file (default: ./)") do |an_output_filename| opt_output_filename = an_output_filename specified_output = true end @@ -583,7 +583,6 @@ class Crystal::Command compiler.link_flags = link_flags.join(' ') unless link_flags.empty? - output_filename = opt_output_filename filenames += opt_filenames.not_nil! arguments = opt_arguments.not_nil! @@ -604,18 +603,23 @@ class Crystal::Command sources.concat gather_sources(filenames) 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 + + # FIXME: The explicit cast should not be necessary (#15472) + output_path = ::Path[opt_output_filename.as?(String) || "./"] + + if output_path.ends_with_separator? || File.directory?(output_path) first_filename = sources.first.filename - output_filename = "#{::Path[first_filename].stem}#{output_extension}" + output_filename = (output_path / "#{::Path[first_filename].stem}#{output_extension}").normalize.to_s # Check if we'll overwrite the main source file if !compiler.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 + else + output_filename = output_path.to_s + if output_path.extension.empty? + output_filename += output_extension + end end output_format ||= allowed_formats[0]