1 /* -*- c-file-style: "java"; indent-tabs-mode: nil -*-
2 *
3 * distcc -- A simple distributed compiler system
4 *
5 * Copyright (C) 2002, 2003, 2004 by Martin Pool
6 * Copyright 2007 Google Inc.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 * USA.
22 */
23
24
25 #include <config.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32
33 #include "distcc.h"
34 #include "trace.h"
35 #include "util.h"
36 #include "exitcode.h"
37
38
39
40 /**
41 * @file
42 *
43 * Everything we know about C filenames.
44 *
45 * We need to have some heuristics about input and output filenames to
46 * understand command lines, because that's what cc does.
47 *
48 * @note As of 0.10, .s and .S files are never distributed, because
49 * they might contain '.include' pseudo-operations, which are resolved
50 * by the assembler.
51 */
52
53
54
55 /**
56 * Return a pointer to the extension, including the dot, or NULL.
57 **/
dcc_find_extension(char * sfile)58 char * dcc_find_extension(char *sfile)
59 {
60 char *dot;
61
62 dot = strrchr(sfile, '.');
63 if (dot == NULL || dot[1] == '\0') {
64 /* make sure there's space for one more character after the
65 * dot */
66 return NULL;
67 }
68 return dot;
69 }
70
71 /**
72 * Return a pointer to the extension, including the dot, or NULL.
73 * Same as dcc_find_extension(), but the argument and return
74 * value are both pointers to const.
75 **/
dcc_find_extension_const(const char * sfile)76 const char * dcc_find_extension_const(const char *sfile) {
77 #if 0
78 return dcc_find_extension((char *) sfile);
79 #else
80 /* The following intermediate variable works around a bug in gcc 4.2.3 where
81 * for the code above gcc spuriously reports "warning: passing argument 1
82 * of 'dcc_find_extension' discards qualifiers from pointer target type",
83 * despite the explicit cast. */
84 char *sfile_nonconst = (char *)sfile;
85 return dcc_find_extension(sfile_nonconst);
86 #endif
87 }
88
89
90 /**
91 * Return a pointer to the basename of the file (everything after the
92 * last slash.) If there is no slash, return the whole filename,
93 * which is presumably in the current directory.
94 **/
dcc_find_basename(const char * sfile)95 const char * dcc_find_basename(const char *sfile)
96 {
97 char *slash;
98
99 if (!sfile)
100 return sfile;
101
102 slash = strrchr(sfile, '/');
103
104 if (slash == NULL || slash[1] == '\0')
105 return sfile;
106
107 return slash+1;
108 }
109
110 /** Truncate the filename to its dirname (everything before the last slash).
111 * If the filename ends with a slash, just lop off the last slash.
112 * Note: this is destructive.
113 */
dcc_truncate_to_dirname(char * file)114 void dcc_truncate_to_dirname(char *file)
115 {
116 char *slash = 0;
117
118 slash = strrchr(file, '/');
119
120 if (slash == NULL) {
121 file[0] = '\0';
122 } else {
123 *slash = '\0';
124 }
125 }
126
127
dcc_set_file_extension(const char * sfile,const char * new_ext,char ** ofile)128 static int dcc_set_file_extension(const char *sfile,
129 const char *new_ext,
130 char **ofile)
131 {
132 char *dot, *o;
133
134 o = strdup(sfile);
135 if (!o) {
136 rs_log_error("strdup failed (out of memory?)");
137 return EXIT_DISTCC_FAILED;
138 }
139 dot = dcc_find_extension(o);
140 if (!dot) {
141 rs_log_error("couldn't find extension in \"%s\"", o);
142 return EXIT_DISTCC_FAILED;
143 }
144 if (strlen(dot) < strlen(new_ext)) {
145 rs_log_error("not enough space for new extension");
146 return EXIT_DISTCC_FAILED;
147 }
148 strcpy(dot, new_ext);
149 *ofile = o;
150
151 return 0;
152 }
153
154
155 /*
156 * Apple extensions:
157 * file.mm, file.M
158 * Objective-C++ source code which must be preprocessed. (APPLE ONLY)
159 *
160 * file.mii Objective-C++ source code which should not be
161 * preprocessed. (APPLE ONLY)
162 *
163 * http://developer.apple.com/techpubs/macosx/DeveloperTools/gcc3/gcc/Overall-Options.html
164 */
165
166
167
168 /**
169 * If you preprocessed a file with extension @p e, what would you get?
170 *
171 * @param e original extension (e.g. ".c")
172 *
173 * @returns preprocessed extension, (e.g. ".i"), or NULL if
174 * unrecognized.
175 **/
dcc_preproc_exten(const char * e)176 const char * dcc_preproc_exten(const char *e)
177 {
178 if (e[0] != '.')
179 return NULL;
180 e++;
181 if (!strcmp(e, "i") || !strcmp(e, "c")) {
182 return ".i";
183 } else if (!strcmp(e, "c") || !strcmp(e, "cc")
184 || !strcmp(e, "cpp") || !strcmp(e, "cxx")
185 || !strcmp(e, "cp") || !strcmp(e, "c++")
186 || !strcmp(e, "C") || !strcmp(e, "ii")) {
187 return ".ii";
188 } else if(!strcmp(e,"mi") || !strcmp(e, "m")) {
189 return ".mi";
190 } else if(!strcmp(e,"mii") || !strcmp(e,"mm")
191 || !strcmp(e,"M")) {
192 return ".mii";
193 } else if (!strcasecmp(e, "s")) {
194 return ".s";
195 } else {
196 return NULL;
197 }
198 }
199
200
201 /**
202 * Does the extension of this file indicate that it is already
203 * preprocessed?
204 **/
dcc_is_preprocessed(const char * sfile)205 int dcc_is_preprocessed(const char *sfile)
206 {
207 const char *dot, *ext;
208 dot = dcc_find_extension_const(sfile);
209 if (!dot)
210 return 0;
211 ext = dot+1;
212
213 switch (ext[0]) {
214 #ifdef ENABLE_REMOTE_ASSEMBLE
215 case 's':
216 /* .S needs to be run through cpp; .s does not */
217 return !strcmp(ext, "s");
218 #endif
219 case 'i':
220 return !strcmp(ext, "i")
221 || !strcmp(ext, "ii");
222 case 'm':
223 return !strcmp(ext, "mi")
224 || !strcmp(ext, "mii");
225 default:
226 return 0;
227 }
228 }
229
230
231 /**
232 * Work out whether @p sfile is source based on extension
233 **/
dcc_is_source(const char * sfile)234 int dcc_is_source(const char *sfile)
235 {
236 const char *dot, *ext;
237 dot = dcc_find_extension_const(sfile);
238 if (!dot)
239 return 0;
240 ext = dot+1;
241
242 /* you could expand this out further into a RE-like set of case
243 * statements, but i'm not sure it's that important. */
244
245 switch (ext[0]) {
246 case 'i':
247 return !strcmp(ext, "i")
248 || !strcmp(ext, "ii");
249 case 'c':
250 return !strcmp(ext, "c")
251 || !strcmp(ext, "cc")
252 || !strcmp(ext, "cpp")
253 || !strcmp(ext, "cxx")
254 || !strcmp(ext, "cp")
255 || !strcmp(ext, "c++");
256 case 'C':
257 return !strcmp(ext, "C");
258 case 'm':
259 return !strcmp(ext,"m")
260 || !strcmp(ext,"mm")
261 || !strcmp(ext,"mi")
262 || !strcmp(ext,"mii");
263 case 'M':
264 return !strcmp(ext, "M");
265 #ifdef ENABLE_REMOTE_ASSEMBLE
266 case 's':
267 return !strcmp(ext, "s");
268 case 'S':
269 return !strcmp(ext, "S");
270 #endif
271 default:
272 return 0;
273 }
274 }
275
276
277
278 /**
279 * Decide whether @p filename is an object file, based on its
280 * extension.
281 **/
dcc_is_object(const char * filename)282 int dcc_is_object(const char *filename)
283 {
284 const char *dot;
285 dot = dcc_find_extension_const(filename);
286 if (!dot)
287 return 0;
288
289 return !strcmp(dot, ".o");
290 }
291
292
293 /* Some files should always be built locally... */
294 int
dcc_source_needs_local(const char * filename)295 dcc_source_needs_local(const char *filename)
296 {
297 const char *p;
298
299 p = dcc_find_basename(filename);
300
301 if (str_startswith("conftest.", p) || str_startswith("tmp.conftest.", p)) {
302 rs_trace("autoconf tests are run locally: %s", filename);
303 return EXIT_DISTCC_FAILED;
304 }
305
306 return 0;
307 }
308
309
310
311 /**
312 * Work out the default object file name the compiler would use if -o
313 * was not specified. We don't need to worry about "a.out" because
314 * we've already determined that -c or -S was specified.
315 *
316 * However, the compiler does put the output file in the current
317 * directory even if the source file is elsewhere, so we need to strip
318 * off all leading directories.
319 *
320 * @param sfile Source filename. Assumed to match one of the
321 * recognized patterns, otherwise bad things might happen.
322 **/
dcc_output_from_source(const char * sfile,const char * out_extn,char ** ofile)323 int dcc_output_from_source(const char *sfile,
324 const char *out_extn,
325 char **ofile)
326 {
327 char *slash;
328
329 if ((slash = strrchr(sfile, '/')))
330 sfile = slash+1;
331 if (strlen(sfile) < 3) {
332 rs_log_error("source file %s is bogus", sfile);
333 return EXIT_DISTCC_FAILED;
334 }
335
336 return dcc_set_file_extension(sfile, out_extn, ofile);
337 }
338