| 1 | /* Wrapper for ar/ranlib/nm to pass the LTO plugin. |
| 2 | Copyright (C) 2011-2025 Free Software Foundation, Inc. |
| 3 | Contributed by Andi Kleen. |
| 4 | |
| 5 | This file is part of GCC. |
| 6 | |
| 7 | GCC is free software; you can redistribute it and/or modify it under |
| 8 | the terms of the GNU General Public License as published by the Free |
| 9 | Software Foundation; either version 3, or (at your option) any later |
| 10 | version. |
| 11 | |
| 12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| 13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 15 | for more details. |
| 16 | |
| 17 | You should have received a copy of the GNU General Public License |
| 18 | along with GCC; see the file COPYING3. If not see |
| 19 | <http://www.gnu.org/licenses/>. */ |
| 20 | |
| 21 | #include "config.h" |
| 22 | #include "system.h" |
| 23 | #include "libiberty.h" |
| 24 | #include "file-find.h" |
| 25 | |
| 26 | #ifndef PERSONALITY |
| 27 | #error "Please set personality" |
| 28 | #endif |
| 29 | |
| 30 | /* The exec prefix as derived at compile-time from --prefix. */ |
| 31 | |
| 32 | static const char standard_exec_prefix[] = STANDARD_EXEC_PREFIX; |
| 33 | |
| 34 | /* The libexec prefix as derived at compile-time from --prefix. */ |
| 35 | |
| 36 | static const char standard_libexec_prefix[] = STANDARD_LIBEXEC_PREFIX; |
| 37 | |
| 38 | /* The bindir prefix as derived at compile-time from --prefix. */ |
| 39 | |
| 40 | static const char standard_bin_prefix[] = STANDARD_BINDIR_PREFIX; |
| 41 | |
| 42 | /* A relative path to be used in finding the location of tools |
| 43 | relative to this program. */ |
| 44 | |
| 45 | static const char *const tooldir_base_prefix = TOOLDIR_BASE_PREFIX; |
| 46 | |
| 47 | /* The exec prefix as relocated from the location of this program. */ |
| 48 | |
| 49 | static const char *self_exec_prefix; |
| 50 | |
| 51 | /* The libexec prefix as relocated from the location of this program. */ |
| 52 | |
| 53 | static const char *self_libexec_prefix; |
| 54 | |
| 55 | /* The tools prefix as relocated from the location of this program. */ |
| 56 | |
| 57 | static const char *self_tooldir_prefix; |
| 58 | |
| 59 | /* The name of the machine that is being targeted. */ |
| 60 | |
| 61 | static const char *const target_machine = DEFAULT_TARGET_MACHINE; |
| 62 | |
| 63 | /* The target version. */ |
| 64 | |
| 65 | static const char *const target_version = DEFAULT_TARGET_VERSION; |
| 66 | |
| 67 | /* The collection of target specific path prefixes. */ |
| 68 | |
| 69 | static struct path_prefix target_path; |
| 70 | |
| 71 | /* The collection path prefixes. */ |
| 72 | |
| 73 | static struct path_prefix path; |
| 74 | |
| 75 | /* The directory separator. */ |
| 76 | |
| 77 | static const char dir_separator[] = { DIR_SEPARATOR, 0 }; |
| 78 | |
| 79 | static void |
| 80 | setup_prefixes (const char *exec_path) |
| 81 | { |
| 82 | const char *self; |
| 83 | |
| 84 | self = getenv (name: "GCC_EXEC_PREFIX" ); |
| 85 | if (!self) |
| 86 | self = exec_path; |
| 87 | else |
| 88 | self = concat (self, "gcc-" PERSONALITY, NULL); |
| 89 | |
| 90 | /* Relocate the exec prefix. */ |
| 91 | self_exec_prefix = make_relative_prefix (self, |
| 92 | standard_bin_prefix, |
| 93 | standard_exec_prefix); |
| 94 | if (self_exec_prefix == NULL) |
| 95 | self_exec_prefix = standard_exec_prefix; |
| 96 | |
| 97 | /* Relocate libexec prefix. */ |
| 98 | self_libexec_prefix = make_relative_prefix (self, |
| 99 | standard_bin_prefix, |
| 100 | standard_libexec_prefix); |
| 101 | if (self_libexec_prefix == NULL) |
| 102 | self_libexec_prefix = standard_libexec_prefix; |
| 103 | |
| 104 | |
| 105 | /* Build the relative path to the target-specific tool directory. */ |
| 106 | self_tooldir_prefix = concat (tooldir_base_prefix, target_machine, |
| 107 | dir_separator, NULL); |
| 108 | self_tooldir_prefix = concat (self_exec_prefix, target_machine, |
| 109 | dir_separator, target_version, dir_separator, |
| 110 | self_tooldir_prefix, NULL); |
| 111 | |
| 112 | /* Add the target-specific tool bin prefix. */ |
| 113 | prefix_from_string (concat (self_tooldir_prefix, "bin" , NULL), &target_path); |
| 114 | |
| 115 | /* Add the target-specific libexec prefix. */ |
| 116 | self_libexec_prefix = concat (self_libexec_prefix, target_machine, |
| 117 | dir_separator, target_version, |
| 118 | dir_separator, NULL); |
| 119 | prefix_from_string (self_libexec_prefix, &target_path); |
| 120 | |
| 121 | /* Add path as a last resort. */ |
| 122 | prefix_from_env ("PATH" , &path); |
| 123 | } |
| 124 | |
| 125 | int |
| 126 | main (int ac, char **av) |
| 127 | { |
| 128 | const char *exe_name; |
| 129 | #if HAVE_LTO_PLUGIN > 0 |
| 130 | char *plugin; |
| 131 | const int j = 2; /* Two extra args, --plugin <plugin> */ |
| 132 | #else |
| 133 | const int j = 0; /* No extra args. */ |
| 134 | #endif |
| 135 | int k, status, err; |
| 136 | const char *err_msg; |
| 137 | const char **nargv; |
| 138 | char **old_argv; |
| 139 | const char *rsp_file = NULL; |
| 140 | const char *rsp_arg = NULL; |
| 141 | const char *rsp_argv[3]; |
| 142 | bool is_ar = !strcmp (PERSONALITY, "ar" ); |
| 143 | int exit_code = FATAL_EXIT_CODE; |
| 144 | int i; |
| 145 | |
| 146 | setup_prefixes (av[0]); |
| 147 | |
| 148 | /* Not using getopt for now. */ |
| 149 | for (i = 0; i < ac; i++) |
| 150 | if (startswith (str: av[i], prefix: "-B" )) |
| 151 | { |
| 152 | const char *arg = av[i] + 2; |
| 153 | const char *end; |
| 154 | size_t len; |
| 155 | |
| 156 | memmove (dest: av + i, src: av + i + 1, n: sizeof (char *) * ((ac + 1) - i)); |
| 157 | ac--; |
| 158 | if (*arg == 0) |
| 159 | { |
| 160 | arg = av[i]; |
| 161 | if (!arg) |
| 162 | { |
| 163 | fprintf (stderr, format: "Usage: gcc-ar [-B prefix] ar arguments ...\n" ); |
| 164 | exit (EXIT_FAILURE); |
| 165 | } |
| 166 | memmove (dest: av + i, src: av + i + 1, n: sizeof (char *) * ((ac + 1) - i)); |
| 167 | ac--; |
| 168 | i++; |
| 169 | } |
| 170 | /* else it's a joined argument */ |
| 171 | |
| 172 | len = strlen (s: arg); |
| 173 | if (len > 0) |
| 174 | len--; |
| 175 | end = arg + len; |
| 176 | |
| 177 | /* Always add a dir separator for the prefix list. */ |
| 178 | if (end > arg && !IS_DIR_SEPARATOR (*end)) |
| 179 | { |
| 180 | static const char dir_separator_str[] = { DIR_SEPARATOR, 0 }; |
| 181 | arg = concat (arg, dir_separator_str, NULL); |
| 182 | } |
| 183 | |
| 184 | add_prefix_begin (&path, arg); |
| 185 | add_prefix_begin (&target_path, arg); |
| 186 | break; |
| 187 | } |
| 188 | |
| 189 | #if HAVE_LTO_PLUGIN > 0 |
| 190 | /* Find the GCC LTO plugin */ |
| 191 | plugin = find_a_file (&target_path, LTOPLUGINSONAME, R_OK); |
| 192 | if (!plugin) |
| 193 | { |
| 194 | fprintf (stderr, format: "%s: Cannot find plugin '%s'\n" , av[0], LTOPLUGINSONAME); |
| 195 | exit (status: 1); |
| 196 | } |
| 197 | #endif |
| 198 | |
| 199 | /* Find the wrapped binutils program. */ |
| 200 | exe_name = find_a_file (&target_path, PERSONALITY, X_OK); |
| 201 | if (!exe_name) |
| 202 | { |
| 203 | const char *real_exe_name = PERSONALITY; |
| 204 | #ifdef CROSS_DIRECTORY_STRUCTURE |
| 205 | real_exe_name = concat (target_machine, "-" , PERSONALITY, NULL); |
| 206 | #endif |
| 207 | exe_name = find_a_file (&path, real_exe_name, X_OK); |
| 208 | if (!exe_name) |
| 209 | { |
| 210 | fprintf (stderr, format: "%s: Cannot find binary '%s'\n" , av[0], |
| 211 | real_exe_name); |
| 212 | exit (status: 1); |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | /* Expand any @files before modifying the command line |
| 217 | and use a temporary response file if there were any. */ |
| 218 | old_argv = av; |
| 219 | expandargv (&ac, &av); |
| 220 | if (av != old_argv) |
| 221 | rsp_file = make_temp_file ("" ); |
| 222 | |
| 223 | /* Prepend - if necessary. */ |
| 224 | if (is_ar && av[1] && av[1][0] != '-') |
| 225 | av[1] = concat ("-" , av[1], NULL); |
| 226 | |
| 227 | /* Create new command line with plugin - if we have one, otherwise just |
| 228 | copy the command through. */ |
| 229 | nargv = XCNEWVEC (const char *, ac + j + 1); /* +j plugin args +1 for NULL. */ |
| 230 | nargv[0] = exe_name; |
| 231 | #if HAVE_LTO_PLUGIN > 0 |
| 232 | nargv[1] = "--plugin" ; |
| 233 | nargv[2] = plugin; |
| 234 | #endif |
| 235 | for (k = 1; k < ac; k++) |
| 236 | nargv[j + k] = av[k]; |
| 237 | nargv[j + k] = NULL; |
| 238 | |
| 239 | /* If @file was passed, put nargv into the temporary response |
| 240 | file and then change it to a single @FILE argument, where |
| 241 | FILE is the temporary filename. */ |
| 242 | if (rsp_file) |
| 243 | { |
| 244 | FILE *f; |
| 245 | int status; |
| 246 | f = fopen (filename: rsp_file, modes: "w" ); |
| 247 | if (f == NULL) |
| 248 | { |
| 249 | fprintf (stderr, format: "Cannot open temporary file %s\n" , rsp_file); |
| 250 | exit (status: 1); |
| 251 | } |
| 252 | status = writeargv ( |
| 253 | CONST_CAST2 (char * const *, const char **, nargv) + 1, f); |
| 254 | if (status) |
| 255 | { |
| 256 | fprintf (stderr, format: "Cannot write to temporary file %s\n" , rsp_file); |
| 257 | exit (status: 1); |
| 258 | } |
| 259 | status = fclose (stream: f); |
| 260 | if (EOF == status) |
| 261 | { |
| 262 | fprintf (stderr, format: "Cannot close temporary file %s\n" , rsp_file); |
| 263 | exit (status: 1); |
| 264 | } |
| 265 | rsp_arg = concat ("@" , rsp_file, NULL); |
| 266 | rsp_argv[0] = nargv[0]; |
| 267 | rsp_argv[1] = rsp_arg; |
| 268 | rsp_argv[2] = NULL; |
| 269 | nargv = rsp_argv; |
| 270 | } |
| 271 | |
| 272 | /* Run utility */ |
| 273 | /* ??? the const is misplaced in pex_one's argv? */ |
| 274 | err_msg = pex_one (PEX_LAST|PEX_SEARCH, |
| 275 | executable: exe_name, |
| 276 | CONST_CAST2 (char * const *, const char **, nargv), |
| 277 | pname: concat ("gcc-" , exe_name, NULL), |
| 278 | NULL,NULL, status: &status, err: &err); |
| 279 | if (err_msg) |
| 280 | fprintf (stderr, format: "Error running %s: %s\n" , exe_name, err_msg); |
| 281 | else if (status) |
| 282 | { |
| 283 | if (WIFSIGNALED (status)) |
| 284 | { |
| 285 | int sig = WTERMSIG (status); |
| 286 | fprintf (stderr, format: "%s terminated with signal %d [%s]%s\n" , |
| 287 | exe_name, sig, strsignal (sig: sig), |
| 288 | WCOREDUMP (status) ? ", core dumped" : "" ); |
| 289 | } |
| 290 | else if (WIFEXITED (status)) |
| 291 | exit_code = WEXITSTATUS (status); |
| 292 | } |
| 293 | else |
| 294 | exit_code = SUCCESS_EXIT_CODE; |
| 295 | |
| 296 | if (rsp_file) |
| 297 | unlink (name: rsp_file); |
| 298 | |
| 299 | return exit_code; |
| 300 | } |
| 301 | |