1 | /* Wrapper for ar/ranlib/nm to pass the LTO plugin. |
2 | Copyright (C) 2011-2023 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 | |