1 /* Dependency generator for Makefile fragments. 2 Copyright (C) 2000, 2001, 2003, 2007, 2008, 2009 3 Free Software Foundation, Inc. 4 Contributed by Zack Weinberg, Mar 2000 5 6 This program is free software; you can redistribute it and/or modify it 7 under the terms of the GNU General Public License as published by the 8 Free Software Foundation; either version 3, or (at your option) any 9 later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; see the file COPYING3. If not see 18 <http://www.gnu.org/licenses/>. 19 20 In other words, you are welcome to use, share and improve this program. 21 You are forbidden to forbid anyone else to use, share and improve 22 what you give them. Help stamp out software-hoarding! */ 23 24 #include "config.h" 25 #include "system.h" 26 #include "mkdeps.h" 27 28 /* Keep this structure local to this file, so clients don't find it 29 easy to start making assumptions. */ 30 struct deps 31 { 32 const char **targetv; 33 unsigned int ntargets; /* number of slots actually occupied */ 34 unsigned int targets_size; /* amt of allocated space - in words */ 35 36 const char **depv; 37 unsigned int ndeps; 38 unsigned int deps_size; 39 40 const char **vpathv; 41 size_t *vpathlv; 42 unsigned int nvpaths; 43 unsigned int vpaths_size; 44 }; 45 46 static const char *munge (const char *); 47 48 /* Given a filename, quote characters in that filename which are 49 significant to Make. Note that it's not possible to quote all such 50 characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are 51 not properly handled. It isn't possible to get this right in any 52 current version of Make. (??? Still true? Old comment referred to 53 3.76.1.) */ 54 55 static const char * 56 munge (const char *filename) 57 { 58 int len; 59 const char *p, *q; 60 char *dst, *buffer; 61 62 for (p = filename, len = 0; *p; p++, len++) 63 { 64 switch (*p) 65 { 66 case ' ': 67 case '\t': 68 /* GNU make uses a weird quoting scheme for white space. 69 A space or tab preceded by 2N+1 backslashes represents 70 N backslashes followed by space; a space or tab 71 preceded by 2N backslashes represents N backslashes at 72 the end of a file name; and backslashes in other 73 contexts should not be doubled. */ 74 for (q = p - 1; filename <= q && *q == '\\'; q--) 75 len++; 76 len++; 77 break; 78 79 case '$': 80 /* '$' is quoted by doubling it. */ 81 len++; 82 break; 83 84 case '#': 85 /* '#' is quoted with a backslash. */ 86 len++; 87 break; 88 } 89 } 90 91 /* Now we know how big to make the buffer. */ 92 buffer = XNEWVEC (char, len + 1); 93 94 for (p = filename, dst = buffer; *p; p++, dst++) 95 { 96 switch (*p) 97 { 98 case ' ': 99 case '\t': 100 for (q = p - 1; filename <= q && *q == '\\'; q--) 101 *dst++ = '\\'; 102 *dst++ = '\\'; 103 break; 104 105 case '$': 106 *dst++ = '$'; 107 break; 108 109 case '#': 110 *dst++ = '\\'; 111 break; 112 113 default: 114 /* nothing */; 115 } 116 *dst = *p; 117 } 118 119 *dst = '\0'; 120 return buffer; 121 } 122 123 /* If T begins with any of the partial pathnames listed in d->vpathv, 124 then advance T to point beyond that pathname. */ 125 static const char * 126 apply_vpath (struct deps *d, const char *t) 127 { 128 if (d->vpathv) 129 { 130 unsigned int i; 131 for (i = 0; i < d->nvpaths; i++) 132 { 133 if (!filename_ncmp (d->vpathv[i], t, d->vpathlv[i])) 134 { 135 const char *p = t + d->vpathlv[i]; 136 if (!IS_DIR_SEPARATOR (*p)) 137 goto not_this_one; 138 139 /* Do not simplify $(vpath)/../whatever. ??? Might not 140 be necessary. */ 141 if (p[1] == '.' && p[2] == '.' && IS_DIR_SEPARATOR (p[3])) 142 goto not_this_one; 143 144 /* found a match */ 145 t = t + d->vpathlv[i] + 1; 146 break; 147 } 148 not_this_one:; 149 } 150 } 151 152 /* Remove leading ./ in any case. */ 153 while (t[0] == '.' && IS_DIR_SEPARATOR (t[1])) 154 { 155 t += 2; 156 /* If we removed a leading ./, then also remove any /s after the 157 first. */ 158 while (IS_DIR_SEPARATOR (t[0])) 159 ++t; 160 } 161 162 return t; 163 } 164 165 /* Public routines. */ 166 167 struct deps * 168 deps_init (void) 169 { 170 return XCNEW (struct deps); 171 } 172 173 void 174 deps_free (struct deps *d) 175 { 176 unsigned int i; 177 178 if (d->targetv) 179 { 180 for (i = 0; i < d->ntargets; i++) 181 free ((void *) d->targetv[i]); 182 free (d->targetv); 183 } 184 185 if (d->depv) 186 { 187 for (i = 0; i < d->ndeps; i++) 188 free ((void *) d->depv[i]); 189 free (d->depv); 190 } 191 192 if (d->vpathv) 193 { 194 for (i = 0; i < d->nvpaths; i++) 195 free ((void *) d->vpathv[i]); 196 free (d->vpathv); 197 free (d->vpathlv); 198 } 199 200 free (d); 201 } 202 203 /* Adds a target T. We make a copy, so it need not be a permanent 204 string. QUOTE is true if the string should be quoted. */ 205 void 206 deps_add_target (struct deps *d, const char *t, int quote) 207 { 208 if (d->ntargets == d->targets_size) 209 { 210 d->targets_size = d->targets_size * 2 + 4; 211 d->targetv = XRESIZEVEC (const char *, d->targetv, d->targets_size); 212 } 213 214 t = apply_vpath (d, t); 215 if (quote) 216 t = munge (t); /* Also makes permanent copy. */ 217 else 218 t = xstrdup (t); 219 220 d->targetv[d->ntargets++] = t; 221 } 222 223 /* Sets the default target if none has been given already. An empty 224 string as the default target in interpreted as stdin. The string 225 is quoted for MAKE. */ 226 void 227 deps_add_default_target (struct deps *d, const char *tgt) 228 { 229 /* Only if we have no targets. */ 230 if (d->ntargets) 231 return; 232 233 if (tgt[0] == '\0') 234 deps_add_target (d, "-", 1); 235 else 236 { 237 #ifndef TARGET_OBJECT_SUFFIX 238 # define TARGET_OBJECT_SUFFIX ".o" 239 #endif 240 const char *start = lbasename (tgt); 241 char *o = (char *) alloca (strlen (start) 242 + strlen (TARGET_OBJECT_SUFFIX) + 1); 243 char *suffix; 244 245 strcpy (o, start); 246 247 suffix = strrchr (o, '.'); 248 if (!suffix) 249 suffix = o + strlen (o); 250 strcpy (suffix, TARGET_OBJECT_SUFFIX); 251 252 deps_add_target (d, o, 1); 253 } 254 } 255 256 void 257 deps_add_dep (struct deps *d, const char *t) 258 { 259 t = munge (apply_vpath (d, t)); /* Also makes permanent copy. */ 260 261 if (d->ndeps == d->deps_size) 262 { 263 d->deps_size = d->deps_size * 2 + 8; 264 d->depv = XRESIZEVEC (const char *, d->depv, d->deps_size); 265 } 266 d->depv[d->ndeps++] = t; 267 } 268 269 void 270 deps_add_vpath (struct deps *d, const char *vpath) 271 { 272 const char *elem, *p; 273 char *copy; 274 size_t len; 275 276 for (elem = vpath; *elem; elem = p) 277 { 278 for (p = elem; *p && *p != ':'; p++); 279 len = p - elem; 280 copy = XNEWVEC (char, len + 1); 281 memcpy (copy, elem, len); 282 copy[len] = '\0'; 283 if (*p == ':') 284 p++; 285 286 if (d->nvpaths == d->vpaths_size) 287 { 288 d->vpaths_size = d->vpaths_size * 2 + 8; 289 d->vpathv = XRESIZEVEC (const char *, d->vpathv, d->vpaths_size); 290 d->vpathlv = XRESIZEVEC (size_t, d->vpathlv, d->vpaths_size); 291 } 292 d->vpathv[d->nvpaths] = copy; 293 d->vpathlv[d->nvpaths] = len; 294 d->nvpaths++; 295 } 296 } 297 298 void 299 deps_write (const struct deps *d, FILE *fp, unsigned int colmax) 300 { 301 unsigned int size, i, column; 302 303 column = 0; 304 if (colmax && colmax < 34) 305 colmax = 34; 306 307 for (i = 0; i < d->ntargets; i++) 308 { 309 size = strlen (d->targetv[i]); 310 column += size; 311 if (i) 312 { 313 if (colmax && column > colmax) 314 { 315 fputs (" \\\n ", fp); 316 column = 1 + size; 317 } 318 else 319 { 320 putc (' ', fp); 321 column++; 322 } 323 } 324 fputs (d->targetv[i], fp); 325 } 326 327 putc (':', fp); 328 column++; 329 330 for (i = 0; i < d->ndeps; i++) 331 { 332 size = strlen (d->depv[i]); 333 column += size; 334 if (colmax && column > colmax) 335 { 336 fputs (" \\\n ", fp); 337 column = 1 + size; 338 } 339 else 340 { 341 putc (' ', fp); 342 column++; 343 } 344 fputs (d->depv[i], fp); 345 } 346 putc ('\n', fp); 347 } 348 349 void 350 deps_phony_targets (const struct deps *d, FILE *fp) 351 { 352 unsigned int i; 353 354 for (i = 1; i < d->ndeps; i++) 355 { 356 putc ('\n', fp); 357 fputs (d->depv[i], fp); 358 putc (':', fp); 359 putc ('\n', fp); 360 } 361 } 362 363 /* Write out a deps buffer to a file, in a form that can be read back 364 with deps_restore. Returns nonzero on error, in which case the 365 error number will be in errno. */ 366 367 int 368 deps_save (struct deps *deps, FILE *f) 369 { 370 unsigned int i; 371 372 /* The cppreader structure contains makefile dependences. Write out this 373 structure. */ 374 375 /* The number of dependences. */ 376 if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1) 377 return -1; 378 /* The length of each dependence followed by the string. */ 379 for (i = 0; i < deps->ndeps; i++) 380 { 381 size_t num_to_write = strlen (deps->depv[i]); 382 if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1) 383 return -1; 384 if (fwrite (deps->depv[i], num_to_write, 1, f) != 1) 385 return -1; 386 } 387 388 return 0; 389 } 390 391 /* Read back dependency information written with deps_save into 392 the deps buffer. The third argument may be NULL, in which case 393 the dependency information is just skipped, or it may be a filename, 394 in which case that filename is skipped. */ 395 396 int 397 deps_restore (struct deps *deps, FILE *fd, const char *self) 398 { 399 unsigned int i, count; 400 size_t num_to_read; 401 size_t buf_size = 512; 402 char *buf = XNEWVEC (char, buf_size); 403 404 /* Number of dependences. */ 405 if (fread (&count, 1, sizeof (count), fd) != sizeof (count)) 406 return -1; 407 408 /* The length of each dependence string, followed by the string. */ 409 for (i = 0; i < count; i++) 410 { 411 /* Read in # bytes in string. */ 412 if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t)) 413 return -1; 414 if (buf_size < num_to_read + 1) 415 { 416 buf_size = num_to_read + 1 + 127; 417 buf = XRESIZEVEC (char, buf, buf_size); 418 } 419 if (fread (buf, 1, num_to_read, fd) != num_to_read) 420 return -1; 421 buf[num_to_read] = '\0'; 422 423 /* Generate makefile dependencies from .pch if -nopch-deps. */ 424 if (self != NULL && filename_cmp (buf, self) != 0) 425 deps_add_dep (deps, buf); 426 } 427 428 free (buf); 429 return 0; 430 } 431