| #!/usr/bin/env ruby |
| |
| # Copyright (C) 2020 Igalia S. L. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| # THE POSSIBILITY OF SUCH DAMAGE. |
| |
| # Wrapper for a .cpp -> .o compilation command. It |
| # 1. converts the command to generate a `.s' file |
| # 2. runs the ASM postprocessor on it to generate the final `.s` file |
| # 3. assembles the `.s` file to a `.o` file |
| |
| $asm_suffix_pre = ".pre.s" |
| $asm_suffix = ".s" |
| $postprocessor = "#{File.dirname($0)}/resolve-asm-file-conflicts.rb" |
| |
| |
| $intermediate_paths = [] |
| |
| # We need to work with indices a lot and unfortunately 'getoptlong' in |
| # the standard library doesn't expose optind, so we're going with |
| # array searches for simplicity. |
| def index_nofail(ary, f, errmsg) |
| idx = ary.index { |el| |
| f.call(el) |
| } |
| if idx.nil? |
| $stderr.puts(errmsg) |
| exit(3) |
| end |
| idx |
| end |
| |
| # Find and return the source file for this compilation command, |
| # removing it from the args. Note that the path (A) as it appears here |
| # (coming from a cmake rule) is likely to be different to the |
| # anonymous argument (B) to the compilation command. However, A will |
| # be a suffix of B. |
| # |
| # Exit with an error if the argument is not there. This has already |
| # been checked by `cxx-wrapper`, otherwise we wouldn't be running. |
| def extract_input!(args) |
| prefix = '-DPOSTPROCESS_ASM=' |
| |
| idx = index_nofail(args, Proc.new { |arg| |
| arg.start_with?(prefix) |
| }, "No `-DPOSTPROCESS_ASM` argument`") |
| |
| path = args[idx][prefix.size..-1] |
| if path.size == 0 |
| $stderr.puts("Empty path in -DPOSTPROCESS_ASM=") |
| exit(3) |
| end |
| # We only need this to be defined for the preprocessor (not any |
| # wrapper) from now on. |
| args[idx] = "-DPOSTPROCESS_ASM" |
| return path |
| end |
| |
| # Get the index of the first argument ending in this suffix. |
| # |
| # Exit with an error if the argument isn't there. We're only ever |
| # called with arguments we know are being passed in by the build |
| # system. |
| def get_arg_idx_suffix(args, wanted) |
| index_nofail(args, Proc.new { |arg| |
| arg.end_with?(wanted) |
| }, "No argument ends with #{wanted}") |
| end |
| |
| # Get index of a given argument. Die if it's not there. |
| def get_arg_idx(args, wanted) |
| index_nofail(args, Proc.new { |arg| |
| arg == wanted |
| }, "No `#{wanted}` argument") |
| end |
| |
| # Get the index of `-o` and verify that an argument follows. |
| # Both are guaranteed to exist (from our build system). |
| def get_o_idx(args) |
| i = get_arg_idx(args, '-o') |
| if (i + 1) >= args.size |
| $stderr.puts("No argument to `-o`") |
| exit(3) |
| end |
| i |
| end |
| |
| # Run command and die if it fails, propagating the exit code. |
| def run_cmd(cmd) |
| pid = Process.spawn(*cmd) |
| Process.waitpid(pid) |
| ret = $? |
| if not ret.success? |
| $stderr.puts("Error running cmd: #{ret}") |
| exit(ret.exitstatus) |
| end |
| end |
| |
| # Convert |
| # cxx -o blah.o -c blah.cpp |
| # to |
| # cxx -o blah.s -S blah.cpp |
| def build_cxx_cmd(args) |
| c_idx = get_arg_idx(args, '-c') |
| o_idx = get_o_idx(args) |
| |
| cxx_args = args.clone |
| |
| cxx_args[c_idx] = '-S' |
| o_path = cxx_args[o_idx + 1] |
| cxx_args[o_idx + 1] = o_path.sub(/[.]o$/, $asm_suffix) |
| $intermediate_paths << cxx_args[o_idx + 1] |
| if cxx_args[o_idx + 1] == o_path |
| $stderr.puts("Output file name not an object file: `#{o_path}`") |
| exit(3) |
| end |
| cxx_args |
| end |
| |
| # Do |
| # mv blah.S blah.pre.S |
| # The reason we do a rename instead of directly generating the .pre.s |
| # file when compiling is so that the corresponding .dwo file will have |
| # the correct name embedded. |
| def rename_s_file(args) |
| o_path = args[get_o_idx(args) + 1] |
| File.rename(o_path.sub(/[.]o$/, $asm_suffix), |
| o_path.sub(/[.]o$/, $asm_suffix_pre)) |
| end |
| |
| # Build |
| # postprocessor blah.pre.S blah.S |
| def build_postprocessor_cmd(args) |
| o_path = args[get_o_idx(args) + 1] |
| |
| pp_args = [ |
| $postprocessor, |
| o_path.sub(/[.]o$/, $asm_suffix_pre), # input |
| o_path.sub(/[.]o$/, $asm_suffix) # output |
| ] |
| $intermediate_paths << pp_args[-2] |
| $intermediate_paths << pp_args[-1] |
| pp_args |
| end |
| |
| # Build |
| # cxx -o blah.o -c blah.S |
| def build_as_cmd(args, i_path) |
| i_idx = get_arg_idx_suffix(args, i_path) |
| o_path = args[get_o_idx(args) + 1] |
| |
| as_args = args.clone |
| i_path = as_args[i_idx] |
| as_args[i_idx] = o_path.sub(/[.]o$/, $asm_suffix) |
| as_args |
| end |
| |
| args = ARGV.to_a |
| i_path = extract_input!(args) |
| |
| begin |
| run_cmd(build_cxx_cmd(args)) |
| rename_s_file(args) |
| run_cmd(build_postprocessor_cmd(args)) |
| run_cmd(build_as_cmd(args, i_path)) |
| ensure |
| $intermediate_paths.each { |p| |
| if File.exist?(p) |
| File.delete(p) |
| end |
| } |
| end |