1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *	 http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <stdint.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 
24 #if !defined(__MINGW32__)
25 #  include <sys/wait.h>
26 #endif
27 
28 #include <unistd.h>
29 #include <dirent.h>
30 #include <errno.h>
31 #include <assert.h>
32 
33 #ifdef __EMX__
34 #  define SHELL_CMD 			"sh"
35 #  define GEN_EXPORTS			"emxexp"
36 #  define DEF2IMPLIB_CMD		"emximp"
37 #  define SHARE_SW			"-Zdll -Zmtd"
38 #  define USE_OMF 1
39 #  define TRUNCATE_DLL_NAME
40 #  define DYNAMIC_LIB_EXT		"dll"
41 #  define EXE_EX			".exe"
42 /* OMF is the native format under OS/2 */
43 #  if USE_OMF
44 
45 #    define STATIC_LIB_EXT		"lib"
46 #    define OBJECT_EXT			"obj"
47 #    define LIBRARIAN			"emxomfar"
48 #    define LIBRARIAN_OPTS		"cr"
49 #  else
50 /* but the alternative, a.out, can fork() which is sometimes necessary */
51 #    define STATIC_LIB_EXT		"a"
52 #    define OBJECT_EXT			"o"
53 #    define LIBRARIAN			"ar"
54 #    define LIBRARIAN_OPTS		"cr"
55 #  endif
56 #endif
57 
58 #if defined(__APPLE__)
59 #  define SHELL_CMD			"/bin/sh"
60 #  define DYNAMIC_LIB_EXT		"dylib"
61 #  define MODULE_LIB_EXT		"bundle"
62 #  define STATIC_LIB_EXT		"a"
63 #  define OBJECT_EXT			"o"
64 #  define LIBRARIAN			"ar"
65 #  define LIBRARIAN_OPTS		"cr"
66 /* man libtool(1) documents ranlib option of -c.  */
67 #  define RANLIB			"ranlib"
68 #  define PIC_FLAG			"-fPIC -fno-common"
69 #  define SHARED_OPTS			"-dynamiclib"
70 #  define MODULE_OPTS			"-bundle -dynamic"
71 #  define DYNAMIC_LINK_OPTS		"-flat_namespace"
72 #  define DYNAMIC_LINK_UNDEFINED	"-undefined suppress"
73 #  define dynamic_link_version_func	darwin_dynamic_link_function
74 #  define DYNAMIC_INSTALL_NAME		"-install_name"
75 #  define DYNAMIC_LINK_NO_INSTALL	"-dylib_file"
76 #  define HAS_REALPATH
77 /*-install_name  /Users/jerenk/apache-2.0-cvs/lib/libapr.0.dylib -compatibility_version 1 -current_version 1.0 */
78 #  define LD_LIBRARY_PATH		"DYLD_LIBRARY_PATH"
79 #  define LD_LIBRARY_PATH_LOCAL		"DYLD_FALLBACK_LIBRARY_PATH"
80 #endif
81 
82 #if defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || (defined(__sun) && defined(__GNUC__))
83 #  define SHELL_CMD 			"/bin/sh"
84 #  define DYNAMIC_LIB_EXT		"so"
85 #  define MODULE_LIB_EXT		"so"
86 #  define STATIC_LIB_EXT		"a"
87 #  define OBJECT_EXT			"o"
88 #  define LIBRARIAN			"ar"
89 #  define LIBRARIAN_OPTS		"cr"
90 #  define RANLIB			"ranlib"
91 #  define PIC_FLAG			"-fPIC"
92 #  define RPATH				"-rpath"
93 #  define SHARED_OPTS			"-shared"
94 #  define MODULE_OPTS			"-shared"
95 #  define LINKER_FLAG_PREFIX		"-Wl,"
96 #if !defined(__sun)
97 #  define DYNAMIC_LINK_OPTS		LINKER_FLAG_PREFIX "-export-dynamic"
98 #else
99 #  define DYNAMIC_LINK_OPTS		""
100 #endif
101 #  define ADD_MINUS_L
102 #  define LD_RUN_PATH			"LD_RUN_PATH"
103 #  define LD_LIBRARY_PATH		"LD_LIBRARY_PATH"
104 #  define LD_LIBRARY_PATH_LOCAL		LD_LIBRARY_PATH
105 #endif
106 
107 #if defined(__sun) && !defined(__GNUC__)
108 #  define SHELL_CMD			"/bin/sh"
109 #  define DYNAMIC_LIB_EXT		"so"
110 #  define MODULE_LIB_EXT		"so"
111 #  define STATIC_LIB_EXT		"a"
112 #  define OBJECT_EXT			"o"
113 #  define LIBRARIAN			"ar"
114 #  define LIBRARIAN_OPTS		"cr"
115 #  define RANLIB			"ranlib"
116 #  define PIC_FLAG			"-fPIC"
117 #  define RPATH				"-R"
118 #  define SHARED_OPTS			"-G"
119 #  define MODULE_OPTS			"-G"
120 #  define DYNAMIC_LINK_OPTS		""
121 #  define LINKER_FLAG_NO_EQUALS
122 #  define ADD_MINUS_L
123 #  define HAS_REALPATH
124 #  define LD_RUN_PATH			"LD_RUN_PATH"
125 #  define LD_LIBRARY_PATH		"LD_LIBRARY_PATH"
126 #  define LD_LIBRARY_PATH_LOCAL		LD_LIBRARY_PATH
127 #endif
128 
129 #if defined(_OSD_POSIX)
130 #  define SHELL_CMD			"/usr/bin/sh"
131 #  define DYNAMIC_LIB_EXT		"so"
132 #  define MODULE_LIB_EXT		"so"
133 #  define STATIC_LIB_EXT		"a"
134 #  define OBJECT_EXT			"o"
135 #  define LIBRARIAN			"ar"
136 #  define LIBRARIAN_OPTS		"cr"
137 #  define SHARED_OPTS			"-G"
138 #  define MODULE_OPTS			"-G"
139 #  define LINKER_FLAG_PREFIX		"-Wl,"
140 #  define NEED_SNPRINTF
141 #endif
142 
143 #if defined(sinix) && defined(mips) && defined(__SNI_TARG_UNIX)
144 #  define SHELL_CMD			"/usr/bin/sh"
145 #  define DYNAMIC_LIB_EXT		"so"
146 #  define MODULE_LIB_EXT		"so"
147 #  define STATIC_LIB_EXT		"a"
148 #  define OBJECT_EXT			"o"
149 #  define LIBRARIAN			"ar"
150 #  define LIBRARIAN_OPTS		"cr"
151 #  define RPATH				"-Brpath"
152 #  define SHARED_OPTS			"-G"
153 #  define MODULE_OPTS			"-G"
154 #  define LINKER_FLAG_PREFIX		"-Wl,"
155 #  define DYNAMIC_LINK_OPTS		LINKER_FLAG_PREFIX "-Blargedynsym"
156 
157 #  define NEED_SNPRINTF
158 #  define LD_RUN_PATH			"LD_RUN_PATH"
159 #  define LD_LIBRARY_PATH		"LD_LIBRARY_PATH"
160 #  define LD_LIBRARY_PATH_LOCAL		LD_LIBRARY_PATH
161 #endif
162 
163 #if defined(__MINGW32__)
164 #  define SHELL_CMD			"sh"
165 #  define DYNAMIC_LIB_EXT		"dll"
166 #  define MODULE_LIB_EXT 		"dll"
167 #  define STATIC_LIB_EXT		"a"
168 #  define OBJECT_EXT			"o"
169 #  define LIBRARIAN			"ar"
170 #  define LIBRARIAN_OPTS		"cr"
171 #  define RANLIB			"ranlib"
172 #  define LINKER_FLAG_PREFIX		"-Wl,"
173 #  define SHARED_OPTS			"-shared"
174 #  define MODULE_OPTS			"-shared"
175 #  define MKDIR_NO_UMASK
176 #  define EXE_EXT			".exe"
177 #endif
178 
179 #ifndef CC
180 #define CC				"clang"
181 #endif
182 
183 #ifndef CXX
184 #define CXX				"g++"
185 #endif
186 
187 #ifndef LINK_C
188 #define LINK_C				"clang"
189 #endif
190 
191 #ifndef LINK_CXX
192 #define LINK_CXX			"g++"
193 #endif
194 
195 #ifndef LIBDIR
196 #define LIBDIR				"/usr/local/lib"
197 #endif
198 
199 #define OBJDIR				".libs"
200 
201 #ifndef SHELL_CMD
202 #error Unsupported platform: Please add defines for SHELL_CMD etc. for your platform.
203 #endif
204 
205 #ifdef NEED_SNPRINTF
206 #include <stdarg.h>
207 #endif
208 
209 #ifdef __EMX__
210 #include <process.h>
211 #endif
212 
213 #ifndef PATH_MAX
214 #define PATH_MAX 1024
215 #endif
216 
217 
218 /* We want to say we are libtool 1.4 for shlibtool compatibility. */
219 #define VERSION "1.4"
220 
221 #define DEBUG(fmt, ...) if(cmd->options.debug) printf(fmt, ## __VA_ARGS__)
222 #define NOTICE(fmt, ...) if(!cmd->options.silent) printf(fmt, ## __VA_ARGS__)
223 #define ERROR(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
224 
225 enum tool_mode {
226 	MODE_UNKNOWN,
227 	MODE_COMPILE,
228 	MODE_LINK,
229 	MODE_EXECUTE,
230 	MODE_INSTALL,
231 };
232 
233 enum output_type {
234 	OUT_GENERAL,
235 	OUT_OBJECT,
236 	OUT_PROGRAM,
237 	OUT_LIB,
238 	OUT_STATIC_LIB_ONLY,
239 	OUT_DYNAMIC_LIB_ONLY,
240 	OUT_MODULE,
241 };
242 
243 enum pic_mode {
244 	PIC_UNKNOWN,
245 	PIC_PREFER,
246 	PIC_AVOID,
247 };
248 
249 enum shared_mode {
250 	SHARE_UNSET,
251 	SHARE_STATIC,
252 	SHARE_SHARED,
253 };
254 
255 enum lib_type {
256 	TYPE_UKNOWN,
257 	TYPE_STATIC_LIB,
258 	TYPE_DYNAMIC_LIB,
259 	TYPE_MODULE_LIB,
260 	TYPE_OBJECT,
261 };
262 
263 typedef struct {
264 	char const **vals;
265 	int num;
266 } count_chars;
267 
268 typedef struct {
269 	char const *normal;
270 	char const *install;
271 } library_name;
272 
273 typedef struct {
274 	count_chars *normal;
275 	count_chars *install;
276 	count_chars *dependencies;
277 } library_opts;
278 
279 typedef struct {
280 	int silent;
281 	int debug;
282 	enum shared_mode shared;
283 	int export_all;
284 	int dry_run;
285 	enum pic_mode pic_mode;
286 	int export_dynamic;
287 	int no_install;
288 } options_t;
289 
290 typedef struct {
291 	enum tool_mode mode;
292 	enum output_type output;
293 	options_t options;
294 
295 	char const *output_name;
296 	char const *fake_output_name;
297 	char const *basename;
298 
299 	char const *install_path;
300 	char const *compiler;
301 	char const *program;
302 	count_chars *program_opts;
303 
304 	count_chars *arglist;
305 	count_chars *tmp_dirs;
306 	count_chars *obj_files;
307 	count_chars *dep_rpaths;
308 	count_chars *rpaths;
309 
310 	library_name static_name;
311 	library_name shared_name;
312 	library_name module_name;
313 
314 	library_opts static_opts;
315 	library_opts shared_opts;
316 
317 	char const *version_info;
318 	char const *undefined_flag;
319 } command_t;
320 
321 #ifdef RPATH
322 static void add_rpath(count_chars *cc, char const *path);
323 #endif
324 
usage(int code)325 static void usage(int code)
326 {
327 	printf("Usage: jlibtool [OPTIONS...] COMMANDS...\n");
328 	printf("jlibtool is a replacement for GNU libtool with similar functionality.\n\n");
329 
330 	printf("  --config	 show all configuration variables\n");
331 	printf("  --debug	  enable verbose shell tracing\n");
332 	printf("  --dry-run	display commands without modifying any files\n");
333 	printf("  --help	   display this help message and exit\n");
334 	printf("  --mode=MODE	   use operational mode MODE (you *must* set mode)\n");
335 
336 	printf("  --silent	 don't print informational messages\n");
337 	printf("  --tag=TAG	Ignored for libtool compatibility\n");
338 	printf("  --version	print version information\n");
339 
340 
341 	printf("  --shared	 Build shared libraries when using --mode=link\n");
342 	printf("  --export-all	   Try to export 'def' file on some platforms\n");
343 
344 	printf("\nMODE must be one of the following:\n\n");
345 	printf("  compile	  compile a source file into a jlibtool object\n");
346 	printf("  execute	  automatically set library path, then run a program\n");
347 	printf("  install	  install libraries or executables\n");
348 	printf("  link	     create a library or an executable\n");
349 
350 	printf("\nMODE-ARGS can be the following:\n\n");
351 	printf("  -export-dynamic  accepted and ignored\n");
352 	printf("  -module	  create a module when linking\n");
353 	printf("  -shared	  create a shared library when linking\n");
354 	printf("  -prefer-pic      prefer position-independent-code when compiling\n");
355 	printf("  -prefer-non-pic  prefer non position-independent-code when compiling\n");
356 	printf("  -static	  create a static library when linking\n");
357 	printf("  -no-install      link libraries locally\n");
358 	printf("  -rpath arg	   Set install path for shared libraries\n");
359 	printf("  -l arg	   pass '-l arg' to the link stage\n");
360 	printf("  -L arg	   pass '-L arg' to the link stage\n");
361 	printf("  -R dir	   add 'dir' to runtime library search path.\n");
362 	printf("  -Zexe	    accepted and ignored\n");
363 	printf("  -avoid-version   accepted and ignored\n");
364 
365 	exit(code);
366 }
367 
368 #if defined(NEED_SNPRINTF)
369 /* Write at most n characters to the buffer in str, return the
370  * number of chars written or -1 if the buffer would have been
371  * overflowed.
372  *
373  * This is portable to any POSIX-compliant system has /dev/null
374  */
375 static FILE *f = NULL;
vsnprintf(char * str,size_t n,char const * fmt,va_list ap)376 static int vsnprintf(char *str, size_t n, char const *fmt, va_list ap)
377 {
378 	int res;
379 
380 	if (!f) {
381 		f = fopen("/dev/null","w");
382 	}
383 
384 	if (!f) {
385 		return -1;
386 	}
387 
388 	setvbuf(f, str, _IOFBF, n);
389 
390 	res = vfprintf(f, fmt, ap);
391 
392 	if ((res > 0) && (res < n)) {
393 		res = vsprintf( str, fmt, ap );
394 	}
395 	return res;
396 }
397 
snprintf(char * str,size_t n,char const * fmt,...)398 static int snprintf(char *str, size_t n, char const *fmt, ...)
399 {
400 	va_list ap;
401 	int res;
402 
403 	va_start(ap, fmt);
404 	res = vsnprintf(str, n, fmt, ap);
405 	va_end(ap);
406 	return res;
407 }
408 #endif
409 
lt_malloc(size_t size)410 static void *lt_malloc(size_t size)
411 {
412 	void *out;
413 
414 	out = malloc(size);
415 	if (!out) {
416 		ERROR("Failed allocating %zu bytes, OOM\n", size);
417 		exit(1);
418 	}
419 
420 	return out;
421 }
422 
lt_const_free(const void * ptr)423 static void lt_const_free(const void *ptr)
424 {
425 	void *tmp;
426 
427 	memcpy(&tmp, &ptr, sizeof(tmp));
428 	free(tmp);
429 }
430 
init_count_chars(count_chars * cc)431 static void init_count_chars(count_chars *cc)
432 {
433 	cc->vals = (char const**) lt_malloc(PATH_MAX*sizeof(char*));
434 	cc->num = 0;
435 }
436 
alloc_countchars(void)437 static count_chars *alloc_countchars(void)
438 {
439 	count_chars *out;
440 	out = lt_malloc(sizeof(count_chars));
441 	if (!out) {
442 		exit(1);
443 	}
444 	init_count_chars(out);
445 
446 	return out;
447 }
448 
clear_count_chars(count_chars * cc)449 static void clear_count_chars(count_chars *cc)
450 {
451 	int i;
452 	for (i = 0; i < cc->num; i++) {
453 		cc->vals[i] = NULL;
454 	}
455 
456 	cc->num = 0;
457 }
458 
push_count_chars(count_chars * cc,char const * newval)459 static void push_count_chars(count_chars *cc, char const *newval)
460 {
461 	cc->vals[cc->num++] = newval;
462 }
463 
pop_count_chars(count_chars * cc)464 static char const *pop_count_chars(count_chars *cc)
465 {
466 	if (!cc->num) {
467 		return NULL;
468 	}
469 	return cc->vals[--cc->num];
470 }
471 
insert_count_chars(count_chars * cc,char const * newval,int position)472 static void insert_count_chars(count_chars *cc, char const *newval, int position)
473 {
474 	int i;
475 
476 	for (i = cc->num; i > position; i--) {
477 		cc->vals[i] = cc->vals[i-1];
478 	}
479 
480 	cc->vals[position] = newval;
481 	cc->num++;
482 }
483 
append_count_chars(count_chars * cc,count_chars * cctoadd)484 static void append_count_chars(count_chars *cc, count_chars *cctoadd)
485 {
486 	int i;
487 	for (i = 0; i < cctoadd->num; i++) {
488 		if (cctoadd->vals[i]) {
489 			push_count_chars(cc, cctoadd->vals[i]);
490 		}
491 	}
492 }
493 
flatten_count_chars(count_chars * cc,char delim)494 static char const *flatten_count_chars(count_chars *cc, char delim)
495 {
496 	int i, size;
497 	char *newval;
498 
499 	size = 0;
500 	for (i = 0; i < cc->num; i++) {
501 		if (cc->vals[i]) {
502 			size += strlen(cc->vals[i]) + 1;
503 			if (delim) {
504 				size++;
505 			}
506 		}
507 	}
508 
509 	newval = (char*)lt_malloc(size + 1);
510 	newval[0] = '\0';
511 
512 	for (i = 0; i < cc->num; i++) {
513 		if (cc->vals[i]) {
514 			strcat(newval, cc->vals[i]);
515 			if (delim) {
516 				size_t len = strlen(newval);
517 				newval[len] = delim;
518 				newval[len + 1] = '\0';
519 			}
520 		}
521 	}
522 
523 	return newval;
524 }
525 
shell_esc(char const * str)526 static char *shell_esc(char const *str)
527 {
528 	int in_quote = 0;
529 	char *cmd;
530 	uint8_t *d;
531 	uint8_t const *s;
532 
533 	cmd = (char *)lt_malloc(2 * strlen(str) + 3);
534 	d = (unsigned char *)cmd;
535 	s = (const unsigned char *)str;
536 
537 #ifdef __MINGW32__
538 	*d++ = '\"';
539 #endif
540 
541 	for (; *s; ++s) {
542 		if (*s == '"') {
543 			*d++ = '\\';
544 			in_quote++;
545 		}
546 		else if (*s == '\\' || (*s == ' ' && (in_quote % 2))) {
547 			*d++ = '\\';
548 		}
549 		*d++ = *s;
550 	}
551 
552 #ifdef __MINGW32__
553 	*d++ = '\"';
554 #endif
555 
556 	*d = '\0';
557 	return cmd;
558 }
559 
external_spawn(command_t * cmd,char const * file,char const ** argv)560 static int external_spawn(command_t *cmd, char const *file, char const **argv)
561 {
562 	file = file;		/* -Wunused */
563 
564 	if (!cmd->options.silent) {
565 		char const **argument = argv;
566 		NOTICE("Executing: ");
567 		while (*argument) {
568 			NOTICE("%s ", *argument);
569 			argument++;
570 		}
571 		puts("");
572 	}
573 
574 	if (cmd->options.dry_run) {
575 		return 0;
576 	}
577 #if defined(__EMX__) || defined(__MINGW32__)
578 	return spawnvp(P_WAIT, argv[0], argv);
579 #else
580 	{
581 		pid_t pid;
582 		pid = fork();
583 		if (pid == 0) {
584 			return execvp(argv[0], (char**)argv);
585 		}
586 		else {
587 			int status;
588 			waitpid(pid, &status, 0);
589 
590 			/*
591 			 *	Exited via exit(status)
592 			 */
593 			if (WIFEXITED(status)) {
594 				return WEXITSTATUS(status);
595 			}
596 
597 #ifdef WTERMSIG
598 			if (WIFSIGNALED(status)) {
599 				return WTERMSIG(status);
600 			}
601 #endif
602 
603 			/*
604 			 *	Some other failure.
605 			 */
606 			return 1;
607 		}
608 	}
609 #endif
610 }
611 
run_command(command_t * cmd,count_chars * cc)612 static int run_command(command_t *cmd, count_chars *cc)
613 {
614 	int ret;
615 	char *command;
616 	char *tmp;
617 	char const *raw;
618 	char const *spawn_args[4];
619 	count_chars tmpcc;
620 
621 	init_count_chars(&tmpcc);
622 
623 	if (cmd->program) {
624 		push_count_chars(&tmpcc, cmd->program);
625 	}
626 
627 	append_count_chars(&tmpcc, cmd->program_opts);
628 
629 	append_count_chars(&tmpcc, cc);
630 
631 	raw = flatten_count_chars(&tmpcc, ' ');
632 	command = shell_esc(raw);
633 
634 	memcpy(&tmp, &raw, sizeof(tmp));
635 	free(tmp);
636 
637 	spawn_args[0] = SHELL_CMD;
638 	spawn_args[1] = "-c";
639 	spawn_args[2] = command;
640 	spawn_args[3] = NULL;
641 	ret = external_spawn(cmd, spawn_args[0], spawn_args);
642 
643 	free(command);
644 
645 	return ret;
646 }
647 
648 /*
649  * print configuration
650  * shlibpath_var is used in configure.
651  */
652 #define printc(_x,_y) if (!value || !strcmp(value, _x)) printf(_x "=\"%s\"\n", _y)
653 
print_config(char const * value)654 static void print_config(char const *value)
655 {
656 #ifdef LD_RUN_PATH
657 	printc("runpath_var", LD_RUN_PATH);
658 #endif
659 #ifdef LD_LIBRARY_PATH
660 	printc("shlibpath_var", LD_LIBRARY_PATH);
661 #endif
662 #ifdef LD_LIBRARY_PATH_LOCAL
663 	printc("shlocallibpath_var", LD_LIBRARY_PATH_LOCAL);
664 #endif
665 #ifdef SHELL_CMD
666 	printc("SHELL", SHELL_CMD);
667 #endif
668 #ifdef OBJECT_EXT
669 	printc("objext", OBJECT_EXT);
670 #endif
671 #ifdef OBJDIR
672 	printc("objdir", OBJDIR);
673 #endif
674 #ifdef DYNAMIC_LIB_EXT
675 	/* add a '.' prefix because libtool does that. */
676 	printc("shrext_cmds", "echo ." DYNAMIC_LIB_EXT);
677 	/* add a '.' prefix because libtool does that. */
678 	printc("shrext", "." DYNAMIC_LIB_EXT);
679 #endif
680 #ifdef EXE_EXT
681 	printc("exeext", EXE_EXT);
682 #endif
683 #ifdef STATIC_LIB_EXT
684 	printc("libext", STATIC_LIB_EXT);
685 #endif
686 #ifdef LIBRARIAN
687 	printc("AR", LIBRARIAN);
688 #endif
689 #ifdef LIBRARIAN_OPTS
690 	printc("AR_FLAGS", LIBRARIAN_OPTS);
691 #endif
692 #ifdef LINKER_FLAG_PREFIX
693 	printc("wl", LINKER_FLAG_PREFIX);
694 #endif
695 #ifdef RANLIB
696 	printc("ranlib", RANLIB);
697 #endif
698 
699 }
700 /*
701  * Add a directory to the runtime library search path.
702  */
add_runtime_dir_lib(char const * arg,command_t * cmd)703 static void add_runtime_dir_lib(char const *arg, command_t *cmd)
704 {
705 #ifdef RPATH
706 	add_rpath(cmd->shared_opts.dependencies, arg);
707 #else
708 	(void) arg;			/* -Wunused */
709 	(void) cmd;
710 #endif
711 }
712 
parse_long_opt(char const * arg,command_t * cmd)713 static int parse_long_opt(char const *arg, command_t *cmd)
714 {
715 	char *equal_pos = strchr(arg, '=');
716 	char var[50];
717 	char value[500];
718 
719 	if (equal_pos) {
720 		strncpy(var, arg, equal_pos - arg);
721 		var[equal_pos - arg] = 0;
722 		if (strlen(equal_pos + 1) >= sizeof(var)) {
723 			return 0;
724 		}
725 		strcpy(value, equal_pos + 1);
726 	} else {
727 		strncpy(var, arg, sizeof(var) - 1);
728 		var[sizeof(var) - 1] = '\0';
729 
730 		value[0] = '\0';
731 	}
732 
733 	if (strcmp(var, "silent") == 0) {
734 		cmd->options.silent = 1;
735 	} else if (strcmp(var, "quiet") == 0) {
736 		cmd->options.silent = 1;
737 	} else if (strcmp(var, "debug") == 0) {
738 		cmd->options.debug = 1;
739 	} else if (strcmp(var, "mode") == 0) {
740 		if (cmd->mode != MODE_UNKNOWN) {
741 			ERROR("Cannot set --mode twice\n");
742 			exit(1);
743 		}
744 
745 		if (strcmp(value, "compile") == 0) {
746 			cmd->mode = MODE_COMPILE;
747 			cmd->output = OUT_OBJECT;
748 
749 		} else if (strcmp(value, "link") == 0) {
750 			cmd->mode = MODE_LINK;
751 			cmd->output = OUT_LIB;
752 
753 		} else if (strcmp(value, "install") == 0) {
754 			cmd->mode = MODE_INSTALL;
755 
756 		} else if (strcmp(value, "execute") == 0) {
757 			cmd->mode = MODE_EXECUTE;
758 
759 		} else {
760 			ERROR("Unknown mode \"%s\"\n", value);
761 			exit(1);
762 		}
763 
764 	} else if (strcmp(var, "shared") == 0) {
765 		if ((cmd->mode == MODE_LINK) && (cmd->output == OUT_GENERAL)) {
766 			cmd->output = OUT_DYNAMIC_LIB_ONLY;
767 		}
768 		cmd->options.shared = SHARE_SHARED;
769 
770 	} else if (strcmp(var, "export-all") == 0) {
771 		cmd->options.export_all = 1;
772 
773 	} else if (strcmp(var, "dry-run") == 0) {
774 		NOTICE("Dry-run mode on!\n");
775 		cmd->options.dry_run = 1;
776 
777 	} else if (strcmp(var, "version") == 0) {
778 		NOTICE("Version " VERSION "\n");
779 
780 	} else if (strcmp(var, "help") == 0) {
781 		usage(0);
782 
783 	} else if (strcmp(var, "config") == 0) {
784 		print_config(value);
785 
786 		exit(0);
787 	} else {
788 		return 0;
789 	}
790 
791 	return 1;
792 }
793 
794 /* Return 1 if we eat it. */
parse_short_opt(char const * arg,command_t * cmd)795 static int parse_short_opt(char const *arg, command_t *cmd)
796 {
797 	if (strcmp(arg, "export-dynamic") == 0) {
798 		cmd->options.export_dynamic = 1;
799 		return 1;
800 	}
801 
802 	if (strcmp(arg, "module") == 0) {
803 		cmd->output = OUT_MODULE;
804 		return 1;
805 	}
806 
807 	if (strcmp(arg, "shared") == 0) {
808 		if (cmd->mode == MODE_LINK) {
809 			cmd->output = OUT_DYNAMIC_LIB_ONLY;
810 		}
811 		cmd->options.shared = SHARE_SHARED;
812 		return 1;
813 	}
814 
815 	if (strcmp(arg, "Zexe") == 0) {
816 		return 1;
817 	}
818 
819 	if (strcmp(arg, "avoid-version") == 0) {
820 		return 1;
821 	}
822 
823 	if (strcmp(arg, "prefer-pic") == 0) {
824 		cmd->options.pic_mode = PIC_PREFER;
825 		return 1;
826 	}
827 
828 	if (strcmp(arg, "prefer-non-pic") == 0) {
829 		cmd->options.pic_mode = PIC_AVOID;
830 		return 1;
831 	}
832 
833 	if (strcmp(arg, "static") == 0) {
834 		if ((cmd->mode == MODE_LINK) && (cmd->output == OUT_LIB)) {
835 			cmd->output = OUT_STATIC_LIB_ONLY;
836 		}
837 		cmd->options.shared = SHARE_STATIC;
838 		return 1;
839 	}
840 
841 	if (cmd->mode == MODE_LINK) {
842 		if (strcmp(arg, "no-install") == 0) {
843 			cmd->options.no_install = 1;
844 			return 1;
845 		}
846 		if (arg[0] == 'L' || arg[0] == 'l') {
847 			/* Hack... */
848 			arg--;
849 			push_count_chars(cmd->shared_opts.dependencies, arg);
850 			return 1;
851 		} else if (arg[0] == 'R' && arg[1]) {
852 			/* -Rdir Add dir to runtime library search path. */
853 			add_runtime_dir_lib(&arg[1], cmd);
854 			return 1;
855 		}
856 	}
857 	return 0;
858 }
859 
860 #ifdef TRUNCATE_DLL_NAME
truncate_dll_name(char * path)861 static char *truncate_dll_name(char *path)
862 {
863 	/* Cut DLL name down to 8 characters after removing any mod_ prefix */
864 	char *tmppath = strdup(path);
865 	char *newname = strrchr(tmppath, '/') + 1;
866 	char *ext = strrchr(newname, '.');
867 	int len;
868 
869 	if (ext == NULL) {
870 		return tmppath;
871 	}
872 
873 	len = ext - newname;
874 
875 	if (strncmp(newname, "mod_", 4) == 0) {
876 		strcpy(newname, newname + 4);
877 		len -= 4;
878 	}
879 
880 	if (len > 8) {
881 		strcpy(newname + 8, strchr(newname, '.'));
882 	}
883 
884 	return tmppath;
885 }
886 #endif
887 
safe_strtol(char const * nptr,char const ** endptr,int base)888 static long safe_strtol(char const *nptr, char const **endptr, int base)
889 {
890 	long rv;
891 
892 	errno = 0;
893 
894 	rv = strtol(nptr, (char**)endptr, 10);
895 
896 	if (errno == ERANGE) {
897 		return 0;
898 	}
899 
900 	return rv;
901 }
902 
safe_mkdir(command_t * cmd,char const * path)903 static void safe_mkdir(command_t *cmd, char const *path)
904 {
905 	int status;
906 	mode_t old_umask;
907 
908 	old_umask = umask(0);
909 	umask(old_umask);
910 
911 #ifdef MKDIR_NO_UMASK
912 	status = mkdir(path);
913 #else
914 	status = mkdir(path, ~old_umask);
915 #endif
916 	if ((status < 0) && (errno != EEXIST)) {
917 		NOTICE("Warning: mkdir of %s failed\n", path);
918 	}
919 }
920 
921 /** Returns a file's name without the path
922  *
923  * @param path to break apart.
924  * @return pointer in path.
925  */
file_name(char const * path)926 static char const *file_name(char const *path)
927 {
928 	char const *name;
929 
930 	name = strrchr(path, '/');
931 	if (!name) {
932 		name = strrchr(path, '\\'); 	/* eww windows? */
933 	}
934 	if (!name) {
935 		name = path;
936 	} else {
937 		name++;
938 	}
939 
940 	return name;
941 }
942 
943 #ifdef GEN_EXPORTS
944 
945 /** Returns a file's name without path or extension
946  *
947  * @param path to check
948  * @return pointer in path.
949  */
file_name_stripped(char const * path)950 static char const *file_name_stripped(char const *path)
951 {
952 	char const *name;
953 	char const *ext;
954 
955 	name = file_name(path);
956 	ext = strrchr(name, '.');
957 
958 	if (ext) {
959 		char *trimmed;
960 
961 		trimmed = lt_malloc(ext - name + 1);
962 		strncpy(trimmed, name, ext - name);
963 		trimmed[ext-name] = 0;
964 
965 		return trimmed;
966 	}
967 
968 	return name;
969 }
970 #endif
971 
972 /* version_info is in the form of MAJOR:MINOR:PATCH */
darwin_dynamic_link_function(char const * version_info)973 static char const *darwin_dynamic_link_function(char const *version_info)
974 {
975 	char *newarg;
976 	long major, minor, patch;
977 
978 	major = 0;
979 	minor = 0;
980 	patch = 0;
981 
982 	if (version_info) {
983 		major = safe_strtol(version_info, &version_info, 10);
984 
985 		if (version_info) {
986 			if (version_info[0] == ':') {
987 				version_info++;
988 			}
989 
990 			minor = safe_strtol(version_info, &version_info, 10);
991 
992 			if (version_info) {
993 				if (version_info[0] == ':') {
994 					version_info++;
995 				}
996 
997 				patch = safe_strtol(version_info, &version_info, 10);
998 
999 			}
1000 		}
1001 	}
1002 
1003 	/* Avoid -dylib_compatibility_version must be greater than zero errors. */
1004 	if (major == 0) {
1005 		major = 1;
1006 	}
1007 	newarg = (char*)lt_malloc(100);
1008 	snprintf(newarg, 99,
1009 			 "-compatibility_version %ld -current_version %ld.%ld",
1010 			 major, major, minor);
1011 
1012 	return newarg;
1013 }
1014 
1015 
1016 /*
1017  *	Add a '.libs/' to the buffer.  The caller ensures that
1018  *	The buffer is large enough to handle 6 extra characters.
1019  */
add_dotlibs(char * buffer)1020 static void add_dotlibs(char *buffer)
1021 {
1022 	char *name = strrchr(buffer, '/');
1023 
1024 	if (!name) {
1025 		if (!buffer[0]) {
1026 			strcpy(buffer, ".libs/");
1027 			return;
1028 		}
1029 		name = buffer;
1030 	} else {
1031 		name++;
1032 	}
1033 	memmove(name + 6, name, strlen(name));
1034 	memcpy(name, ".libs/", 6);
1035 }
1036 
gen_library_name(char const * name,enum lib_type genlib)1037 static char *gen_library_name(char const *name, enum lib_type genlib)
1038 {
1039 	char *newarg, *newext;
1040 
1041 	newarg = (char *)calloc(strlen(name) + 11, 1);
1042 
1043 	if (genlib == TYPE_MODULE_LIB && strncmp(name, "lib", 3) == 0) {
1044 		name += 3;
1045 	}
1046 
1047 	if (genlib == TYPE_MODULE_LIB) {
1048 		strcpy(newarg, file_name(name));
1049 	}
1050 	else {
1051 		strcpy(newarg, name);
1052 	}
1053 
1054 	newext = strrchr(newarg, '.');
1055 	if (!newext) {
1056 		ERROR("Library path does not have an extension\n");
1057 	free(newarg);
1058 
1059 	return NULL;
1060 	}
1061 	newext++;
1062 
1063 	switch (genlib) {
1064 	case TYPE_STATIC_LIB:
1065 		strcpy(newext, STATIC_LIB_EXT);
1066 		break;
1067 	case TYPE_DYNAMIC_LIB:
1068 		strcpy(newext, DYNAMIC_LIB_EXT);
1069 		break;
1070 	case TYPE_MODULE_LIB:
1071 		strcpy(newext, MODULE_LIB_EXT);
1072 		break;
1073 
1074 	default:
1075 		break;
1076 	}
1077 
1078 	add_dotlibs(newarg);
1079 
1080 	return newarg;
1081 }
1082 
gen_install_name(char const * name,enum lib_type genlib)1083 static char *gen_install_name(char const *name, enum lib_type genlib)
1084 {
1085 	char *newname;
1086 	int rv;
1087 	struct stat sb;
1088 
1089 	newname = gen_library_name(name, genlib);
1090 	if (!newname) return NULL;
1091 
1092 	/* Check if it exists. If not, return NULL.  */
1093 	rv = stat(newname, &sb);
1094 
1095 	if (rv) {
1096 		free(newname);
1097 		return NULL;
1098 	}
1099 
1100 	return newname;
1101 }
1102 
check_object_exists(command_t * cmd,char const * arg,int arglen)1103 static char const *check_object_exists(command_t *cmd, char const *arg, int arglen)
1104 {
1105 	char *newarg, *ext;
1106 	struct stat sb;
1107 
1108 	newarg = (char *)lt_malloc(arglen + 10);
1109 	memcpy(newarg, arg, arglen);
1110 	newarg[arglen] = 0;
1111 	ext = newarg + arglen;
1112 
1113 	strcpy(ext, OBJECT_EXT);
1114 
1115 	DEBUG("Checking (obj): %s\n", newarg);
1116 	if (stat(newarg, &sb) == 0) {
1117 		return newarg;
1118 	}
1119 
1120 	free(newarg);
1121 
1122 	return NULL;
1123 }
1124 
1125 /* libdircheck values:
1126  * 0 - no .libs suffix
1127  * 1 - .libs suffix
1128  */
check_library_exists(command_t * cmd,char const * arg,int pathlen,int libdircheck,enum lib_type * libtype)1129 static char *check_library_exists(command_t *cmd, char const *arg, int pathlen,
1130 				  int libdircheck, enum lib_type *libtype)
1131 {
1132 	char *newarg, *ext;
1133 	int pass, rv, newpathlen;
1134 
1135 	newarg = (char *)lt_malloc(strlen(arg) + 10);
1136 	strcpy(newarg, arg);
1137 	newarg[pathlen] = '\0';
1138 
1139 	newpathlen = pathlen;
1140 	if (libdircheck) {
1141 		add_dotlibs(newarg);
1142 		newpathlen += sizeof(".libs/") - 1;
1143 	}
1144 
1145 	strcpy(newarg + newpathlen, arg + pathlen);
1146 	ext = strrchr(newarg, '.');
1147 	if (!ext) {
1148 		ERROR("Error: Library path does not have an extension\n");
1149 		free(newarg);
1150 
1151 		return NULL;
1152 	}
1153 	ext++;
1154 
1155 	pass = 0;
1156 
1157 	do {
1158 		struct stat sb;
1159 
1160 		switch (pass) {
1161 		case 0:
1162 			if (cmd->options.pic_mode != PIC_AVOID &&
1163 				cmd->options.shared != SHARE_STATIC) {
1164 				strcpy(ext, DYNAMIC_LIB_EXT);
1165 				*libtype = TYPE_DYNAMIC_LIB;
1166 				break;
1167 			}
1168 			pass = 1;
1169 			/* Fall through */
1170 		case 1:
1171 			strcpy(ext, STATIC_LIB_EXT);
1172 			*libtype = TYPE_STATIC_LIB;
1173 			break;
1174 		case 2:
1175 			strcpy(ext, MODULE_LIB_EXT);
1176 			*libtype = TYPE_MODULE_LIB;
1177 			break;
1178 		case 3:
1179 			strcpy(ext, OBJECT_EXT);
1180 			*libtype = TYPE_OBJECT;
1181 			break;
1182 		default:
1183 			*libtype = TYPE_UKNOWN;
1184 			break;
1185 		}
1186 
1187 		DEBUG("Checking (lib): %s\n", newarg);
1188 		rv = stat(newarg, &sb);
1189 	}
1190 	while (rv != 0 && ++pass < 4);
1191 
1192 	if (rv == 0) {
1193 		return newarg;
1194 	}
1195 
1196 	free(newarg);
1197 
1198 	return NULL;
1199 }
1200 
load_install_path(char const * arg)1201 static char * load_install_path(char const *arg)
1202 {
1203 	FILE *f;
1204 	char *path;
1205 
1206 	f = fopen(arg,"r");
1207 	if (f == NULL) {
1208 		return NULL;
1209 	}
1210 
1211 	path = lt_malloc(PATH_MAX);
1212 
1213 	fgets(path, PATH_MAX, f);
1214 	fclose(f);
1215 
1216 	if (path[strlen(path)-1] == '\n') {
1217 		path[strlen(path)-1] = '\0';
1218 	}
1219 
1220 	/* Check that we have an absolute path.
1221 	 * Otherwise the file could be a GNU libtool file.
1222 	 */
1223 	if (path[0] != '/') {
1224 		free(path);
1225 
1226 		return NULL;
1227 	}
1228 	return path;
1229 }
1230 
load_noinstall_path(char const * arg,int pathlen)1231 static char *load_noinstall_path(char const *arg, int pathlen)
1232 {
1233 	char *newarg, *expanded_path;
1234 	int newpathlen;
1235 
1236 	newarg = (char *)lt_malloc(strlen(arg) + 10);
1237 	strcpy(newarg, arg);
1238 	newarg[pathlen] = 0;
1239 
1240 	newpathlen = pathlen;
1241 	strcat(newarg, ".libs");
1242 	newpathlen += sizeof(".libs") - 1;
1243 	newarg[newpathlen] = 0;
1244 
1245 #ifdef HAS_REALPATH
1246 	expanded_path = lt_malloc(PATH_MAX);
1247 	expanded_path = realpath(newarg, expanded_path);
1248 	/* Uh, oh.  There was an error.  Fall back on our first guess. */
1249 	if (!expanded_path) {
1250 		expanded_path = newarg;
1251 	}
1252 #else
1253 	/* We might get ../ or something goofy.  Oh, well. */
1254 	expanded_path = newarg;
1255 #endif
1256 
1257 	return expanded_path;
1258 }
1259 
add_dynamic_link_opts(command_t * cmd,count_chars * args)1260 static void add_dynamic_link_opts(command_t *cmd, count_chars *args)
1261 {
1262 #ifdef DYNAMIC_LINK_OPTS
1263 	if (cmd->options.pic_mode != PIC_AVOID) {
1264 		DEBUG("Adding linker opt: %s\n", DYNAMIC_LINK_OPTS);
1265 
1266 		push_count_chars(args, DYNAMIC_LINK_OPTS);
1267 		if (cmd->undefined_flag) {
1268 			push_count_chars(args, "-undefined");
1269 #if defined(__APPLE__)
1270 			/* -undefined dynamic_lookup is used by the bundled Python in
1271 			 * 10.4, but if we don't set MACOSX_DEPLOYMENT_TARGET to 10.3+,
1272 			 * we'll get a linker error if we pass this flag.
1273 			 */
1274 			if (strcasecmp(cmd->undefined_flag, "dynamic_lookup") == 0) {
1275 				insert_count_chars(cmd->program_opts, "MACOSX_DEPLOYMENT_TARGET=10.3", 0);
1276 			}
1277 #endif
1278 			push_count_chars(args, cmd->undefined_flag);
1279 		}
1280 		else {
1281 #ifdef DYNAMIC_LINK_UNDEFINED
1282 			DEBUG("Adding linker opt: %s\n", DYNAMIC_LINK_UNDEFINED);
1283 
1284 			push_count_chars(args, DYNAMIC_LINK_UNDEFINED);
1285 #endif
1286 		}
1287 	}
1288 #endif
1289 }
1290 
1291 /* Read the final install location and add it to runtime library search path. */
1292 #ifdef RPATH
add_rpath(count_chars * cc,char const * path)1293 static void add_rpath(count_chars *cc, char const *path)
1294 {
1295 	int size = 0;
1296 	char *tmp;
1297 
1298 #ifdef LINKER_FLAG_PREFIX
1299 	size = strlen(LINKER_FLAG_PREFIX);
1300 #endif
1301 	size = size + strlen(path) + strlen(RPATH) + 2;
1302 	tmp = lt_malloc(size);
1303 
1304 #ifdef LINKER_FLAG_PREFIX
1305 	strcpy(tmp, LINKER_FLAG_PREFIX);
1306 	strcat(tmp, RPATH);
1307 #else
1308 	strcpy(tmp, RPATH);
1309 #endif
1310 #ifndef LINKER_FLAG_NO_EQUALS
1311 	strcat(tmp, "=");
1312 #endif
1313 	strcat(tmp, path);
1314 
1315 	push_count_chars(cc, tmp);
1316 }
1317 
add_rpath_file(count_chars * cc,char const * arg)1318 static void add_rpath_file(count_chars *cc, char const *arg)
1319 {
1320 	char const *path;
1321 
1322 	path = load_install_path(arg);
1323 	if (path) {
1324 		add_rpath(cc, path);
1325 		lt_const_free(path);
1326 	}
1327 }
1328 
add_rpath_noinstall(count_chars * cc,char const * arg,int pathlen)1329 static void add_rpath_noinstall(count_chars *cc, char const *arg, int pathlen)
1330 {
1331 	char const *path;
1332 
1333 	path = load_noinstall_path(arg, pathlen);
1334 	if (path) {
1335 		add_rpath(cc, path);
1336 		lt_const_free(path);
1337 	}
1338 }
1339 #endif
1340 
1341 #ifdef DYNAMIC_LINK_NO_INSTALL
add_dylink_noinstall(count_chars * cc,char const * arg,int pathlen,int extlen)1342 static void add_dylink_noinstall(count_chars *cc, char const *arg, int pathlen,
1343 						  int extlen)
1344 {
1345 	char const *install_path, *current_path, *name;
1346 	char *exp_argument;
1347 	int i_p_len, c_p_len, name_len, dyext_len, cur_len;
1348 
1349 	install_path = load_install_path(arg);
1350 	current_path = load_noinstall_path(arg, pathlen);
1351 
1352 	if (!install_path || !current_path) {
1353 		return;
1354 	}
1355 
1356 	push_count_chars(cc, DYNAMIC_LINK_NO_INSTALL);
1357 
1358 	i_p_len = strlen(install_path);
1359 	c_p_len = strlen(current_path);
1360 
1361 	name = arg+pathlen;
1362 	name_len = extlen-pathlen;
1363 	dyext_len = sizeof(DYNAMIC_LIB_EXT) - 1;
1364 
1365 	/* No, we need to replace the extension. */
1366 	exp_argument = (char *)lt_malloc(i_p_len + c_p_len + (name_len*2) +
1367 								  (dyext_len*2) + 2);
1368 
1369 	cur_len = 0;
1370 	strcpy(exp_argument, install_path);
1371 	cur_len += i_p_len;
1372 	exp_argument[cur_len++] = '/';
1373 	strncpy(exp_argument+cur_len, name, extlen-pathlen);
1374 	cur_len += name_len;
1375 	strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
1376 	cur_len += dyext_len;
1377 	exp_argument[cur_len++] = ':';
1378 	strcpy(exp_argument+cur_len, current_path);
1379 	cur_len += c_p_len;
1380 	exp_argument[cur_len++] = '/';
1381 	strncpy(exp_argument+cur_len, name, extlen-pathlen);
1382 	cur_len += name_len;
1383 	strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT);
1384 	cur_len += dyext_len;
1385 
1386 	push_count_chars(cc, exp_argument);
1387 }
1388 #endif
1389 
1390 #ifdef ADD_MINUS_L
1391 /* use -L -llibname to allow to use installed libraries */
add_minus_l(count_chars * cc,char const * arg)1392 static void add_minus_l(count_chars *cc, char const *arg)
1393 {
1394 	char *newarg;
1395 	char *name = strrchr(arg, '/');
1396 	char *file = strrchr(arg, '.');
1397 
1398 	if ((name != NULL) && (file != NULL) &&
1399 		(strstr(name, "lib") == (name + 1))) {
1400 		*name = '\0';
1401 		*file = '\0';
1402 		file = name;
1403 		file = file+4;
1404 		push_count_chars(cc, "-L");
1405 		push_count_chars(cc, arg);
1406 		/* we need one argument like -lapr-1 */
1407 		newarg = lt_malloc(strlen(file) + 3);
1408 		strcpy(newarg, "-l");
1409 		strcat(newarg, file);
1410 		push_count_chars(cc, newarg);
1411 	} else {
1412 		push_count_chars(cc, arg);
1413 	}
1414 }
1415 #endif
1416 
1417 #if 0
1418 static void add_linker_flag_prefix(count_chars *cc, char const *arg)
1419 {
1420 #ifndef LINKER_FLAG_PREFIX
1421 	push_count_chars(cc, arg);
1422 #else
1423 	char *newarg;
1424 	newarg = (char*)lt_malloc(strlen(arg) + sizeof(LINKER_FLAG_PREFIX) + 1);
1425 	strcpy(newarg, LINKER_FLAG_PREFIX);
1426 	strcat(newarg, arg);
1427 	push_count_chars(cc, newarg);
1428 #endif
1429 }
1430 #endif
1431 
explode_static_lib(command_t * cmd,char const * lib)1432 static int explode_static_lib(command_t *cmd, char const *lib)
1433 {
1434 	count_chars tmpdir_cc, libname_cc;
1435 	char const *tmpdir, *libname;
1436 	char savewd[PATH_MAX];
1437 	char const *name;
1438 	DIR *dir;
1439 	struct dirent *entry;
1440 	char const *lib_args[4];
1441 
1442 	/* Bah! */
1443 	if (cmd->options.dry_run) {
1444 		return 0;
1445 	}
1446 
1447 	name = file_name(lib);
1448 
1449 	init_count_chars(&tmpdir_cc);
1450 	push_count_chars(&tmpdir_cc, ".libs/");
1451 	push_count_chars(&tmpdir_cc, name);
1452 	push_count_chars(&tmpdir_cc, ".exploded/");
1453 	tmpdir = flatten_count_chars(&tmpdir_cc, 0);
1454 
1455 	NOTICE("Making: %s\n", tmpdir);
1456 
1457 	safe_mkdir(cmd, tmpdir);
1458 
1459 	push_count_chars(cmd->tmp_dirs, tmpdir);
1460 
1461 	getcwd(savewd, sizeof(savewd));
1462 
1463 	if (chdir(tmpdir) != 0) {
1464 		NOTICE("Warning: could not explode %s\n", lib);
1465 
1466 		return 1;
1467 	}
1468 
1469 	if (lib[0] == '/') {
1470 		libname = lib;
1471 	}
1472 	else {
1473 		init_count_chars(&libname_cc);
1474 		push_count_chars(&libname_cc, "../../");
1475 		push_count_chars(&libname_cc, lib);
1476 		libname = flatten_count_chars(&libname_cc, 0);
1477 	}
1478 
1479 	lib_args[0] = LIBRARIAN;
1480 	lib_args[1] = "x";
1481 	lib_args[2] = libname;
1482 	lib_args[3] = NULL;
1483 
1484 	external_spawn(cmd, LIBRARIAN, lib_args);
1485 
1486 	chdir(savewd);
1487 	dir = opendir(tmpdir);
1488 
1489 	while ((entry = readdir(dir)) != NULL) {
1490 #if defined(__APPLE__) && defined(RANLIB)
1491 		/* Apple inserts __.SYMDEF which isn't needed.
1492 		 * Leopard (10.5+) can also add '__.SYMDEF SORTED' which isn't
1493 		 * much fun either.  Just skip them.
1494 		 */
1495 		if (strstr(entry->d_name, "__.SYMDEF") != NULL) {
1496 			continue;
1497 		}
1498 #endif
1499 		if (entry->d_name[0] != '.') {
1500 			push_count_chars(&tmpdir_cc, entry->d_name);
1501 			name = flatten_count_chars(&tmpdir_cc, 0);
1502 
1503 			DEBUG("Adding object: %s\n", name);
1504 			push_count_chars(cmd->obj_files, name);
1505 			pop_count_chars(&tmpdir_cc);
1506 		}
1507 	}
1508 
1509 	closedir(dir);
1510 	return 0;
1511 }
1512 
parse_input_file_name(char const * arg,command_t * cmd)1513 static int parse_input_file_name(char const *arg, command_t *cmd)
1514 {
1515 	char const *ext = strrchr(arg, '.');
1516 	char const *name;
1517 	int pathlen;
1518 	enum lib_type libtype;
1519 	char const *newarg;
1520 
1521 	/* Can't guess the extension */
1522 	if (!ext) {
1523 		return 0;
1524 	}
1525 
1526 	ext++;
1527 	name = file_name(arg);
1528 	pathlen = name - arg;
1529 
1530 	/*
1531 	 *	Were linking and have an archived object or object file
1532 	 *	push it onto the list of object files which'll get used
1533 	 *	to create the input files list for the linker.
1534 	 *
1535 	 *	We assume that these are outside of the project were building,
1536 	 *	as there's no reason to create .a files as part of the build
1537 	 *	process.
1538 	 */
1539 	if (!strcmp(ext, STATIC_LIB_EXT) && (cmd->mode == MODE_LINK)) {
1540 		struct stat sb;
1541 
1542 		if (!stat(arg, &sb)) {
1543 			DEBUG("Adding object: %s\n", arg);
1544 
1545 			push_count_chars(cmd->obj_files, arg);
1546 
1547 			return 1;
1548 		}
1549 	}
1550 
1551 	/*
1552 	 *	More object files, if were linking they get set as input
1553 	 *	files.
1554 	 */
1555 	if (!strcmp(ext, "lo") || !strcmp(ext, OBJECT_EXT)) {
1556 		newarg = check_object_exists(cmd, arg, ext - arg);
1557 		if (!newarg) {
1558 			ERROR("Can not find suitable object file for %s\n", arg);
1559 			exit(1);
1560 		}
1561 
1562 		if (cmd->mode == MODE_LINK) {
1563 			DEBUG("Adding object: %s\n", newarg);
1564 
1565 			push_count_chars(cmd->obj_files, newarg);
1566 		} else {
1567 			push_count_chars(cmd->arglist, newarg);
1568 		}
1569 
1570 		return 1;
1571 	}
1572 
1573 	if (!strcmp(ext, "la")) {
1574 		switch (cmd->mode) {
1575 		case MODE_LINK:
1576 			/* Try the .libs dir first! */
1577 			newarg = check_library_exists(cmd, arg, pathlen, 1, &libtype);
1578 			if (!newarg) {
1579 				/* Try the normal dir next. */
1580 				newarg = check_library_exists(cmd, arg, pathlen, 0, &libtype);
1581 				if (!newarg) {
1582 					ERROR("Can not find suitable library for %s\n", arg);
1583 					exit(1);
1584 				}
1585 			}
1586 
1587 			/* It is not ok to just add the file: a library may added with:
1588 			   1 - -L path library_name. (For *.so in Linux).
1589 			   2 - library_name.
1590 			 */
1591 #ifdef ADD_MINUS_L
1592 			if (libtype == TYPE_DYNAMIC_LIB) {
1593 				add_minus_l(cmd->shared_opts.dependencies, newarg);
1594 			} else if (cmd->output == OUT_LIB &&
1595 					   libtype == TYPE_STATIC_LIB) {
1596 				explode_static_lib(cmd, newarg);
1597 			} else {
1598 				push_count_chars(cmd->shared_opts.dependencies, newarg);
1599 			}
1600 #else
1601 			if (cmd->output == OUT_LIB && libtype == TYPE_STATIC_LIB) {
1602 				explode_static_lib(cmd, newarg);
1603 			}
1604 			else {
1605 				push_count_chars(cmd->shared_opts.dependencies, newarg);
1606 			}
1607 #endif
1608 			if (libtype == TYPE_DYNAMIC_LIB) {
1609 				if (cmd->options.no_install) {
1610 #ifdef RPATH
1611 					add_rpath_noinstall(cmd->shared_opts.dependencies,
1612 										arg, pathlen);
1613 #endif
1614 				}
1615 				else {
1616 #ifdef RPATH
1617 					add_rpath_file(cmd->shared_opts.dependencies, arg);
1618 #endif
1619 				}
1620 			}
1621 			break;
1622 		case MODE_INSTALL:
1623 			/*
1624 			 *	If we've already recorded a library to
1625 			 *	install, we're most likely getting the .la
1626 			 *	file that we want to install as.
1627 			 *
1628 			 *	The problem is that we need to add it as the
1629 			 *	directory, not the .la file itself.
1630 			 *	Otherwise, we'll do odd things.
1631 			 */
1632 			if (cmd->output == OUT_LIB) {
1633 				char *tmp;
1634 
1635 				tmp = strdup(arg);
1636 				tmp[pathlen] = '\0';
1637 				push_count_chars(cmd->arglist, tmp);
1638 
1639 			} else {
1640 				cmd->output = OUT_LIB;
1641 				cmd->output_name = arg;
1642 				cmd->static_name.install = gen_install_name(arg, 0);
1643 				cmd->shared_name.install = gen_install_name(arg, 1);
1644 				cmd->module_name.install = gen_install_name(arg, 2);
1645 
1646 				if (!cmd->static_name.install &&
1647 					!cmd->shared_name.install &&
1648 					!cmd->module_name.install) {
1649 					ERROR("Files to install do not exist\n");
1650 					exit(1);
1651 				}
1652 
1653 			}
1654 			break;
1655 		default:
1656 			break;
1657 		}
1658 
1659 		return 1;
1660 	}
1661 
1662 	if (!strcmp(ext, "c")) {
1663 		/* If we don't already have an idea what our output name will be. */
1664 		if (!cmd->basename) {
1665 			char *tmp = lt_malloc(strlen(arg) + 4);
1666 			strcpy(tmp, arg);
1667 			strcpy(strrchr(tmp, '.') + 1, "lo");
1668 
1669 			cmd->basename = tmp;
1670 
1671 			cmd->fake_output_name = strrchr(cmd->basename, '/');
1672 			if (cmd->fake_output_name) {
1673 				cmd->fake_output_name++;
1674 			} else {
1675 				cmd->fake_output_name = cmd->basename;
1676 			}
1677 		}
1678 	}
1679 
1680 	return 0;
1681 }
1682 
parse_output_file_name(char const * arg,command_t * cmd)1683 static int parse_output_file_name(char const *arg, command_t *cmd)
1684 {
1685 	char const *name;
1686 	char const *ext;
1687 	char *newarg = NULL;
1688 	size_t pathlen;
1689 
1690 	cmd->fake_output_name = arg;
1691 
1692 	name = file_name(arg);
1693 	ext = strrchr(name, '.');
1694 
1695 #ifdef EXE_EXT
1696 	if (!ext || strcmp(ext, EXE_EXT) == 0) {
1697 #else
1698 	if (!ext) {
1699 #endif
1700 		cmd->basename = arg;
1701 		cmd->output = OUT_PROGRAM;
1702 #if defined(_OSD_POSIX)
1703 		cmd->options.pic_mode = PIC_AVOID;
1704 #endif
1705 		newarg = (char *)lt_malloc(strlen(arg) + 5);
1706 		strcpy(newarg, arg);
1707 #ifdef EXE_EXT
1708 	if (!ext) {
1709 	  strcat(newarg, EXE_EXT);
1710 	}
1711 #endif
1712 		cmd->output_name = newarg;
1713 		return 1;
1714 	}
1715 
1716 	ext++;
1717 	pathlen = name - arg;
1718 
1719 	if (strcmp(ext, "la") == 0) {
1720 		assert(cmd->mode == MODE_LINK);
1721 
1722 		cmd->basename = arg;
1723 		cmd->static_name.normal = gen_library_name(arg, TYPE_STATIC_LIB);
1724 		cmd->shared_name.normal = gen_library_name(arg, TYPE_DYNAMIC_LIB);
1725 		cmd->module_name.normal = gen_library_name(arg, TYPE_MODULE_LIB);
1726 		cmd->static_name.install = gen_install_name(arg, TYPE_STATIC_LIB);
1727 		cmd->shared_name.install = gen_install_name(arg, TYPE_DYNAMIC_LIB);
1728 		cmd->module_name.install = gen_install_name(arg, TYPE_MODULE_LIB);
1729 
1730 		if (!cmd->options.dry_run) {
1731 			char *newname;
1732 			char *newext;
1733 			newname = lt_malloc(strlen(cmd->static_name.normal) + 1);
1734 
1735 			strcpy(newname, cmd->static_name.normal);
1736 			newext = strrchr(newname, '/');
1737 			if (!newext) {
1738 				/* Check first to see if the dir already exists! */
1739 				safe_mkdir(cmd, ".libs");
1740 			} else {
1741 				*newext = '\0';
1742 				safe_mkdir(cmd, newname);
1743 			}
1744 			free(newname);
1745 		}
1746 
1747 #ifdef TRUNCATE_DLL_NAME
1748 		if (shared) {
1749 			arg = truncate_dll_name(arg);
1750 		}
1751 #endif
1752 
1753 		cmd->output_name = arg;
1754 		return 1;
1755 	}
1756 
1757 	if (strcmp(ext, STATIC_LIB_EXT) == 0) {
1758 		assert(cmd->mode == MODE_LINK);
1759 
1760 		cmd->basename = arg;
1761 		cmd->options.shared = SHARE_STATIC;
1762 		cmd->output = OUT_STATIC_LIB_ONLY;
1763 		cmd->static_name.normal = gen_library_name(arg, TYPE_STATIC_LIB);
1764 		cmd->static_name.install = gen_install_name(arg, TYPE_STATIC_LIB);
1765 
1766 		if (!cmd->options.dry_run) {
1767 			char *newname;
1768 			char *newext;
1769 			newname = lt_malloc(strlen(cmd->static_name.normal) + 1);
1770 
1771 			strcpy(newname, cmd->static_name.normal);
1772 			newext = strrchr(newname, '/');
1773 			if (!newext) {
1774 				/* Check first to see if the dir already exists! */
1775 				safe_mkdir(cmd, ".libs");
1776 			} else {
1777 				*newext = '\0';
1778 				safe_mkdir(cmd, newname);
1779 			}
1780 			free(newname);
1781 		}
1782 
1783 		cmd->output_name = arg;
1784 		return 1;
1785 	}
1786 
1787 	if (strcmp(ext, DYNAMIC_LIB_EXT) == 0) {
1788 		assert(cmd->mode == MODE_LINK);
1789 
1790 		cmd->basename = arg;
1791 		cmd->options.shared = SHARE_SHARED;
1792 		cmd->output = OUT_DYNAMIC_LIB_ONLY;
1793 		cmd->shared_name.normal = gen_library_name(arg, TYPE_DYNAMIC_LIB);
1794 		cmd->module_name.normal = gen_library_name(arg, TYPE_MODULE_LIB);
1795 		cmd->shared_name.install = gen_install_name(arg, TYPE_DYNAMIC_LIB);
1796 		cmd->module_name.install = gen_install_name(arg, TYPE_MODULE_LIB);
1797 
1798 		if (!cmd->options.dry_run) {
1799 			char *newname;
1800 			char *newext;
1801 			newname = lt_malloc(strlen(cmd->shared_name.normal) + 1);
1802 
1803 			strcpy(newname, cmd->shared_name.normal);
1804 			newext = strrchr(newname, '/');
1805 			if (!newext) {
1806 				/* Check first to see if the dir already exists! */
1807 				safe_mkdir(cmd, ".libs");
1808 			} else {
1809 				*newext = '\0';
1810 				safe_mkdir(cmd, newname);
1811 			}
1812 			free(newname);
1813 		}
1814 
1815 		cmd->output_name = arg;
1816 		return 1;
1817 	}
1818 
1819 	if (strcmp(ext, "lo") == 0) {
1820 		char *newext;
1821 		cmd->basename = arg;
1822 		cmd->output = OUT_OBJECT;
1823 		newarg = (char *)lt_malloc(strlen(arg) + 2);
1824 		strcpy(newarg, arg);
1825 		newext = strrchr(newarg, '.') + 1;
1826 		strcpy(newext, OBJECT_EXT);
1827 		cmd->output_name = newarg;
1828 		return 1;
1829 	}
1830 
1831 	if (strcmp(ext, DYNAMIC_LIB_EXT) == 0) {
1832 		ERROR("Please build libraries with .la target, not ."
1833 		      DYNAMIC_LIB_EXT "\n");
1834 
1835 		exit(1);
1836 	}
1837 
1838 	if (strcmp(ext, STATIC_LIB_EXT) == 0) {
1839 		ERROR("Please build libraries with .la target, not ."
1840 		      STATIC_LIB_EXT "\n");
1841 
1842 		exit(1);
1843 	}
1844 
1845 	return 0;
1846 }
1847 
1848 static char const *automode(char const *arg, command_t *cmd)
1849 {
1850 	if (cmd->mode != MODE_UNKNOWN) return arg;
1851 
1852 	if (!strcmp(arg, "CC") ||
1853 	    !strcmp(arg, "CXX")) {
1854 		DEBUG("Now in compile mode, guessed from: %s\n", arg);
1855 		arg = CC;
1856 		cmd->mode = MODE_COMPILE;
1857 
1858 	} else if (!strcmp(arg, "LINK") ||
1859 		   !strcmp(arg, "LINK.c") ||
1860 		   !strcmp(arg, "LINK.cxx")) {
1861 		DEBUG("Now in linker mode, guessed from: %s\n", arg);
1862 		arg = LINK_C;
1863 		cmd->mode = MODE_LINK;
1864 	}
1865 
1866 	return arg;
1867 }
1868 
1869 
1870 #ifdef GEN_EXPORTS
1871 static void generate_def_file(command_t *cmd)
1872 {
1873 	char def_file[1024];
1874 	char implib_file[1024];
1875 	char *ext;
1876 	FILE *hDef;
1877 	char *export_args[1024];
1878 	int num_export_args = 0;
1879 	char *cmd;
1880 	int cmd_size = 0;
1881 	int a;
1882 
1883 	if (cmd->output_name) {
1884 		strcpy(def_file, cmd->output_name);
1885 		strcat(def_file, ".def");
1886 		hDef = fopen(def_file, "w");
1887 
1888 		if (hDef != NULL) {
1889 			fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", file_name_stripped(cmd->output_name));
1890 			fprintf(hDef, "DATA NONSHARED\n");
1891 			fprintf(hDef, "EXPORTS\n");
1892 			fclose(hDef);
1893 
1894 			for (a = 0; a < cmd->num_obj_files; a++) {
1895 				cmd_size += strlen(cmd->obj_files[a]) + 1;
1896 			}
1897 
1898 			cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3;
1899 			cmd = (char *)lt_malloc(cmd_size);
1900 			strcpy(cmd, GEN_EXPORTS);
1901 
1902 			for (a=0; a < cmd->num_obj_files; a++) {
1903 				strcat(cmd, " ");
1904 				strcat(cmd, cmd->obj_files[a] );
1905 			}
1906 
1907 			strcat(cmd, ">>");
1908 			strcat(cmd, def_file);
1909 			puts(cmd);
1910 			export_args[num_export_args++] = SHELL_CMD;
1911 			export_args[num_export_args++] = "-c";
1912 			export_args[num_export_args++] = cmd;
1913 			export_args[num_export_args++] = NULL;
1914 			external_spawn(cmd, export_args[0], (char const**)export_args);
1915 			cmd->arglist[cmd->num_args++] = strdup(def_file);
1916 
1917 			/* Now make an import library for the dll */
1918 			num_export_args = 0;
1919 			export_args[num_export_args++] = DEF2IMPLIB_CMD;
1920 			export_args[num_export_args++] = "-o";
1921 
1922 			strcpy(implib_file, ".libs/");
1923 			strcat(implib_file, cmd->basename);
1924 			ext = strrchr(implib_file, '.');
1925 
1926 			if (ext) {
1927 				*ext = '\0';
1928 			}
1929 
1930 			strcat(implib_file, ".");
1931 			strcat(implib_file, STATIC_LIB_EXT);
1932 
1933 			export_args[num_export_args++] = implib_file;
1934 			export_args[num_export_args++] = def_file;
1935 			export_args[num_export_args++] = NULL;
1936 			external_spawn(cmd, export_args[0], (char const**)export_args);
1937 
1938 		}
1939 	}
1940 }
1941 #endif
1942 
1943 #if 0
1944 static char const* expand_path(char const *relpath)
1945 {
1946 	char foo[PATH_MAX], *newpath;
1947 
1948 	getcwd(foo, PATH_MAX-1);
1949 	newpath = (char*)lt_malloc(strlen(foo)+strlen(relpath)+2);
1950 	strcpy(newpath, foo);
1951 	strcat(newpath, "/");
1952 	strcat(newpath, relpath);
1953 	return newpath;
1954 }
1955 #endif
1956 
1957 static void link_fixup(command_t *cmd)
1958 {
1959 	/* If we were passed an -rpath directive, we need to build
1960 	 * shared objects too.  Otherwise, we should only create static
1961 	 * libraries.
1962 	 */
1963 	if (!cmd->install_path && (cmd->output == OUT_DYNAMIC_LIB_ONLY ||
1964 		cmd->output == OUT_MODULE || cmd->output == OUT_LIB)) {
1965 		if (cmd->options.shared == SHARE_SHARED) {
1966 			cmd->install_path = LIBDIR;
1967 		}
1968 	}
1969 
1970 	if (cmd->output == OUT_DYNAMIC_LIB_ONLY ||
1971 		cmd->output == OUT_MODULE ||
1972 		cmd->output == OUT_LIB) {
1973 
1974 		push_count_chars(cmd->shared_opts.normal, "-o");
1975 		if (cmd->output == OUT_MODULE) {
1976 			push_count_chars(cmd->shared_opts.normal, cmd->module_name.normal);
1977 		} else {
1978 			push_count_chars(cmd->shared_opts.normal, cmd->shared_name.normal);
1979 #ifdef DYNAMIC_INSTALL_NAME
1980 			push_count_chars(cmd->shared_opts.normal, DYNAMIC_INSTALL_NAME);
1981 
1982 			if (!cmd->install_path) {
1983 				ERROR("Installation mode requires -rpath\n");
1984 				exit(1);
1985 			}
1986 
1987 			{
1988 				char *tmp = lt_malloc(PATH_MAX);
1989 				strcpy(tmp, cmd->install_path);
1990 
1991 				if (cmd->shared_name.install) {
1992 					strcat(tmp, strrchr(cmd->shared_name.install, '/'));
1993 				} else {
1994 					strcat(tmp, strrchr(cmd->shared_name.normal, '/'));
1995 				}
1996 
1997 				push_count_chars(cmd->shared_opts.normal, tmp);
1998 			}
1999 #endif
2000 		}
2001 
2002 		append_count_chars(cmd->shared_opts.normal, cmd->obj_files);
2003 		append_count_chars(cmd->shared_opts.normal, cmd->shared_opts.dependencies);
2004 
2005 		if (cmd->options.export_all) {
2006 #ifdef GEN_EXPORTS
2007 			generate_def_file(cmd);
2008 #endif
2009 		}
2010 	}
2011 
2012 	if (cmd->output == OUT_LIB || cmd->output == OUT_STATIC_LIB_ONLY) {
2013 		push_count_chars(cmd->static_opts.normal, "-o");
2014 		push_count_chars(cmd->static_opts.normal, cmd->output_name);
2015 	}
2016 
2017 	if (cmd->output == OUT_PROGRAM) {
2018 		if (cmd->output_name) {
2019 			push_count_chars(cmd->arglist, "-o");
2020 			push_count_chars(cmd->arglist, cmd->output_name);
2021 			append_count_chars(cmd->arglist, cmd->obj_files);
2022 			append_count_chars(cmd->arglist, cmd->shared_opts.dependencies);
2023 			add_dynamic_link_opts(cmd, cmd->arglist);
2024 		}
2025 	}
2026 }
2027 
2028 static void post_parse_fixup(command_t *cmd)
2029 {
2030 	switch (cmd->mode) {
2031 	case MODE_COMPILE:
2032 #ifdef PIC_FLAG
2033 		if (cmd->options.pic_mode != PIC_AVOID) {
2034 			push_count_chars(cmd->arglist, PIC_FLAG);
2035 		}
2036 #endif
2037 		if (cmd->output_name) {
2038 			push_count_chars(cmd->arglist, "-o");
2039 			push_count_chars(cmd->arglist, cmd->output_name);
2040 		}
2041 		break;
2042 	case MODE_LINK:
2043 		link_fixup(cmd);
2044 		break;
2045 	case MODE_INSTALL:
2046 		if (cmd->output == OUT_LIB) {
2047 			link_fixup(cmd);
2048 		}
2049 	default:
2050 		break;
2051 	}
2052 
2053 #ifdef USE_OMF
2054 	if (cmd->output == OUT_OBJECT ||
2055 		cmd->output == OUT_PROGRAM ||
2056 		cmd->output == OUT_LIB ||
2057 		cmd->output == OUT_DYNAMIC_LIB_ONLY) {
2058 		push_count_chars(cmd->arglist, "-Zomf");
2059 	}
2060 #endif
2061 
2062 	if (cmd->options.shared &&
2063 			(cmd->output == OUT_OBJECT ||
2064 			 cmd->output == OUT_LIB ||
2065 			 cmd->output == OUT_DYNAMIC_LIB_ONLY)) {
2066 #ifdef SHARE_SW
2067 		push_count_chars(cmd->arglist, SHARE_SW);
2068 #endif
2069 	}
2070 }
2071 
2072 static int run_mode(command_t *cmd)
2073 {
2074 	int rv = 0;
2075 	count_chars *cctemp;
2076 
2077 	cctemp = (count_chars*)lt_malloc(sizeof(count_chars));
2078 	init_count_chars(cctemp);
2079 
2080 	switch (cmd->mode) {
2081 	case MODE_COMPILE:
2082 		rv = run_command(cmd, cmd->arglist);
2083 		if (rv) goto finish;
2084 		break;
2085 	case MODE_INSTALL:
2086 		/* Well, we'll assume it's a file going to a directory... */
2087 		/* For brain-dead install-sh based scripts, we have to repeat
2088 		 * the command N-times.  install-sh should die.
2089 		 */
2090 		if (!cmd->output_name) {
2091 			rv = run_command(cmd, cmd->arglist);
2092 			if (rv) goto finish;
2093 		}
2094 		if (cmd->output_name) {
2095 			append_count_chars(cctemp, cmd->arglist);
2096 			insert_count_chars(cctemp,
2097 							   cmd->output_name,
2098 							   cctemp->num - 1);
2099 			rv = run_command(cmd, cctemp);
2100 			if (rv) goto finish;
2101 			clear_count_chars(cctemp);
2102 		}
2103 		if (cmd->static_name.install) {
2104 			append_count_chars(cctemp, cmd->arglist);
2105 			insert_count_chars(cctemp,
2106 							   cmd->static_name.install,
2107 							   cctemp->num - 1);
2108 			rv = run_command(cmd, cctemp);
2109 			if (rv) goto finish;
2110 #if defined(__APPLE__) && defined(RANLIB)
2111 			/* From the Apple libtool(1) manpage on Tiger/10.4:
2112 			 * ----
2113 			 * With  the way libraries used to be created, errors were possible
2114 			 * if the library was modified with ar(1) and  the  table  of
2115 			 * contents  was  not updated  by  rerunning ranlib(1).  Thus the
2116 			 * link editor, ld, warns when the modification date of a library
2117 			 * is more  recent  than  the  creation date  of its table of
2118 			 * contents.  Unfortunately, this means that you get the warning
2119 			 * even if you only copy the library.
2120 			 * ----
2121 			 *
2122 			 * This means that when we install the static archive, we need to
2123 			 * rerun ranlib afterwards.
2124 			 */
2125 			char const *lib_args[3], *static_lib_name;
2126 
2127 			{
2128 				char *tmp;
2129 				size_t len1, len2;
2130 
2131 				len1 = strlen(cmd->arglist->vals[cmd->arglist->num - 1]);
2132 
2133 				static_lib_name = file_name(cmd->static_name.install);
2134 				len2 = strlen(static_lib_name);
2135 
2136 				tmp = lt_malloc(len1 + len2 + 2);
2137 
2138 				snprintf(tmp, len1 + len2 + 2, "%s/%s",
2139 						cmd->arglist->vals[cmd->arglist->num - 1],
2140 						static_lib_name);
2141 
2142 				lib_args[0] = RANLIB;
2143 				lib_args[1] = tmp;
2144 				lib_args[2] = NULL;
2145 
2146 				external_spawn(cmd, RANLIB, lib_args);
2147 
2148 				free(tmp);
2149 			}
2150 #endif
2151 			clear_count_chars(cctemp);
2152 		}
2153 		if (cmd->shared_name.install) {
2154 			append_count_chars(cctemp, cmd->arglist);
2155 			insert_count_chars(cctemp, cmd->shared_name.install,
2156 					   cctemp->num - 1);
2157 			rv = run_command(cmd, cctemp);
2158 			if (rv) goto finish;
2159 			clear_count_chars(cctemp);
2160 		}
2161 		if (cmd->module_name.install) {
2162 			append_count_chars(cctemp, cmd->arglist);
2163 			insert_count_chars(cctemp, cmd->module_name.install,
2164 					   cctemp->num - 1);
2165 			rv = run_command(cmd, cctemp);
2166 			if (rv) goto finish;
2167 			clear_count_chars(cctemp);
2168 		}
2169 		break;
2170 	case MODE_LINK:
2171 		if (cmd->output == OUT_STATIC_LIB_ONLY ||
2172 			cmd->output == OUT_LIB) {
2173 #ifdef RANLIB
2174 			char const *lib_args[3];
2175 #endif
2176 			/* Removes compiler! */
2177 			cmd->program = LIBRARIAN;
2178 			push_count_chars(cmd->program_opts, LIBRARIAN_OPTS);
2179 			push_count_chars(cmd->program_opts, cmd->static_name.normal);
2180 
2181 			rv = run_command(cmd, cmd->obj_files);
2182 			if (rv) goto finish;
2183 
2184 #ifdef RANLIB
2185 			lib_args[0] = RANLIB;
2186 			lib_args[1] = cmd->static_name.normal;
2187 			lib_args[2] = NULL;
2188 			external_spawn(cmd, RANLIB, lib_args);
2189 #endif
2190 		}
2191 
2192 		if (cmd->output == OUT_DYNAMIC_LIB_ONLY ||
2193 			cmd->output == OUT_MODULE ||
2194 			cmd->output == OUT_LIB) {
2195 			cmd->program = NULL;
2196 			clear_count_chars(cmd->program_opts);
2197 
2198 			append_count_chars(cmd->program_opts, cmd->arglist);
2199 			if (cmd->output == OUT_MODULE) {
2200 #ifdef MODULE_OPTS
2201 				push_count_chars(cmd->program_opts, MODULE_OPTS);
2202 #endif
2203 			} else {
2204 #ifdef SHARED_OPTS
2205 				push_count_chars(cmd->program_opts, SHARED_OPTS);
2206 #endif
2207 #ifdef dynamic_link_version_func
2208 				push_count_chars(cmd->program_opts,
2209 						 dynamic_link_version_func(cmd->version_info));
2210 #endif
2211 			}
2212 			add_dynamic_link_opts(cmd, cmd->program_opts);
2213 
2214 			rv = run_command(cmd, cmd->shared_opts.normal);
2215 			if (rv) goto finish;
2216 		}
2217 		if (cmd->output == OUT_PROGRAM) {
2218 			rv = run_command(cmd, cmd->arglist);
2219 			if (rv) goto finish;
2220 		}
2221 		break;
2222 	case MODE_EXECUTE:
2223 	{
2224 		char *l, libpath[PATH_MAX];
2225 
2226 		if (!cmd->arglist->num) {
2227 			ERROR("No command to execute.\n");
2228 			rv = 1;
2229 
2230 			goto finish;
2231 		}
2232 
2233 		if (strlen(cmd->arglist->vals[0]) >= PATH_MAX) {
2234 			ERROR("Libpath too long no buffer space\n");
2235 			rv = 1;
2236 
2237 			goto finish;
2238 		}
2239 
2240 		strcpy(libpath, cmd->arglist->vals[0]);
2241 		add_dotlibs(libpath);
2242 		l = strrchr(libpath, '/');
2243 		if (!l) l = strrchr(libpath, '\\');
2244 		if (l) {
2245 			*l = '\0';
2246 			l = libpath;
2247 		} else {
2248 			l = ".libs/";
2249 		}
2250 
2251 		l = "./build/lib/.libs";
2252 		setenv(LD_LIBRARY_PATH_LOCAL, l, 1);
2253 #ifdef __APPLE__
2254 		setenv("DYLD_FALLBACK_LIBRARY_PATH", l, 1);
2255 #endif
2256 		setenv("FR_LIBRARY_PATH", "./build/lib/local/.libs", 1);
2257 		rv = run_command(cmd, cmd->arglist);
2258 		if (rv) goto finish;
2259 	}
2260 		break;
2261 
2262 	default:
2263 		break;
2264 	}
2265 
2266 	finish:
2267 
2268 	free(cctemp);
2269 	return rv;
2270 }
2271 
2272 static void cleanup_tmp_dir(char const *dirname)
2273 {
2274 	DIR *dir;
2275 	struct dirent *entry;
2276 	char fullname[1024];
2277 
2278 	dir = opendir(dirname);
2279 	if (!dir) {
2280 		return;
2281 	}
2282 
2283 	if ((strlen(dirname) + 1 + sizeof(entry->d_name)) >= sizeof(fullname)) {
2284 		ERROR("Dirname too long, out of buffer space\n");
2285 
2286 		(void) closedir(dir);
2287 		return;
2288 	}
2289 
2290 	while ((entry = readdir(dir)) != NULL) {
2291 		if (entry->d_name[0] != '.') {
2292 			strcpy(fullname, dirname);
2293 			strcat(fullname, "/");
2294 			strcat(fullname, entry->d_name);
2295 			(void) remove(fullname);
2296 		}
2297 	}
2298 
2299 	rmdir(dirname);
2300 
2301 	(void) closedir(dir);
2302 }
2303 
2304 static void cleanup_tmp_dirs(command_t *cmd)
2305 {
2306 	int d;
2307 
2308 	for (d = 0; d < cmd->tmp_dirs->num; d++) {
2309 		cleanup_tmp_dir(cmd->tmp_dirs->vals[d]);
2310 	}
2311 }
2312 
2313 static int ensure_fake_uptodate(command_t *cmd)
2314 {
2315 	/* FIXME: could do the stat/touch here, but nah... */
2316 	char const *touch_args[3];
2317 
2318 	if (cmd->mode == MODE_INSTALL) {
2319 		return 0;
2320 	}
2321 	if (!cmd->fake_output_name) {
2322 		return 0;
2323 	}
2324 
2325 	touch_args[0] = "touch";
2326 	touch_args[1] = cmd->fake_output_name;
2327 	touch_args[2] = NULL;
2328 	return external_spawn(cmd, "touch", touch_args);
2329 }
2330 
2331 /* Store the install path in the *.la file */
2332 static int add_for_runtime(command_t *cmd)
2333 {
2334 	if (cmd->mode == MODE_INSTALL) {
2335 		return 0;
2336 	}
2337 	if (cmd->output == OUT_DYNAMIC_LIB_ONLY ||
2338 		cmd->output == OUT_LIB) {
2339 		FILE *f=fopen(cmd->fake_output_name,"w");
2340 		if (f == NULL) {
2341 			return -1;
2342 		}
2343 		fprintf(f,"%s\n", cmd->install_path);
2344 		fclose(f);
2345 		return(0);
2346 	} else {
2347 		return(ensure_fake_uptodate(cmd));
2348 	}
2349 }
2350 
2351 static void parse_args(int argc, char *argv[], command_t *cmd)
2352 {
2353 	int a;
2354 	char const *arg, *base;
2355 	int arg_used;
2356 
2357 	/*
2358 	 *	We now take a major step past libtool.
2359 	 *
2360 	 *	IF there's no "--mode=...", AND we recognise
2361 	 *	the binary as a "special" name, THEN replace it
2362 	 * 	with the correct one, and set the correct mode.
2363 	 *
2364 	 *	For example if were called 'CC' then we know we should
2365 	 *	probably be compiling stuff.
2366 	 */
2367 	base = file_name(argv[0]);
2368 	arg = automode(base, cmd);
2369 	if (arg != base) {
2370 		push_count_chars(cmd->arglist, arg);
2371 
2372 		assert(cmd->mode != MODE_UNKNOWN);
2373 	}
2374 
2375 	/*
2376 	 *	We first pass over the command-line arguments looking for
2377 	 *	"--mode", etc.  If so, then use the libtool compatibility
2378 	 *	method for building the software.  Otherwise, auto-detect it
2379 	 * 	via "-o" and the extensions.
2380 	 */
2381 	base = NULL;
2382 	if (cmd->mode == MODE_UNKNOWN) for (a = 1; a < argc; a++) {
2383 		arg = argv[a];
2384 
2385 		if (strncmp(arg, "--mode=", 7) == 0) {
2386 			base = NULL;
2387 			break;
2388 		}
2389 
2390 		/*
2391 		 *	Stop if we get another magic method
2392 		 */
2393 		if ((a == 1) &&
2394 		    ((strncmp(arg, "LINK", 4) == 0) ||
2395 		     (strcmp(arg, "CC") == 0) ||
2396 		     (strcmp(arg, "CXX") == 0))) {
2397 			base = NULL;
2398 			break;
2399 		}
2400 
2401 		if (strncmp(arg, "-o", 2) == 0) {
2402 			base = argv[++a];
2403 		}
2404 	}
2405 
2406 	/*
2407 	 *	There were no magic args or an explicit --mode= but we did
2408 	 *	find an output file, so guess what mode were meant to be in
2409 	 *	from its extension.
2410 	 */
2411 	if (base) {
2412 		arg = strrchr(base, '.');
2413 		if (!arg) {
2414 			cmd->mode = MODE_LINK;
2415 			push_count_chars(cmd->arglist, LINK_C);
2416 		}
2417 #ifdef EXE_EXT
2418 		else if (strcmp(arg, EXE_EXT) == 0) {
2419 			cmd->mode = MODE_LINK;
2420 			push_count_chars(cmd->arglist, LINK_C);
2421 		}
2422 #endif
2423 		else if (strcmp(arg + 1, DYNAMIC_LIB_EXT) == 0) {
2424 			cmd->mode = MODE_LINK;
2425 			push_count_chars(cmd->arglist, LINK_C);
2426 		}
2427 		else if (strcmp(arg + 1, STATIC_LIB_EXT) == 0) {
2428 			cmd->mode = MODE_LINK;
2429 			push_count_chars(cmd->arglist, LINK_C);
2430 		}
2431 		else if (strcmp(arg + 1, "la") == 0) {
2432 			cmd->mode = MODE_LINK;
2433 			push_count_chars(cmd->arglist, LINK_C);
2434 		}
2435 		else if ((strcmp(arg + 1, "lo") == 0) ||
2436 			 (strcmp(arg + 1, "o") == 0)) {
2437 			cmd->mode = MODE_COMPILE;
2438 			push_count_chars(cmd->arglist, CC);
2439 		}
2440 	}
2441 
2442 	for (a = 1; a < argc; a++) {
2443 		arg = argv[a];
2444 		arg_used = 1;
2445 
2446 		if (cmd->mode == MODE_EXECUTE) {
2447 			push_count_chars(cmd->arglist, arg);
2448 			continue;
2449 		}
2450 
2451 		if (arg[0] == '-') {
2452 			/*
2453 			 *	Double dashed (long) single dash (short)
2454 			 */
2455 			arg_used = (arg[1] == '-') ?
2456 				parse_long_opt(arg + 2, cmd) :
2457 				parse_short_opt(arg + 1, cmd);
2458 
2459 			if (arg_used) continue;
2460 
2461 			/*
2462 			 *	Ignore all options after the '--execute'
2463 			 */
2464 			if (cmd->mode == MODE_EXECUTE) continue;
2465 
2466 			/*
2467 			 *	We haven't done anything with it yet, but
2468 			 *	there are still some arg/value pairs.
2469 			 *
2470 			 *	Try some of the more complicated short opts...
2471 			 */
2472 			if (a + 1 < argc) {
2473 				/*
2474 				 *	We found an output file!
2475 				 */
2476 				if ((arg[1] == 'o') && (arg[2] == '\0')) {
2477 					arg = argv[++a];
2478 					arg_used = parse_output_file_name(arg,
2479 									  cmd);
2480 				/*
2481 				 *	-MT literal dependency
2482 				 */
2483 				} else if (!strcmp(arg + 1, "MT")) {
2484 					DEBUG("Adding: %s\n", arg);
2485 
2486 					push_count_chars(cmd->arglist, arg);
2487 					arg = argv[++a];
2488 
2489 					NOTICE(" %s\n", arg);
2490 
2491 					push_count_chars(cmd->arglist, arg);
2492 					arg_used = 1;
2493 				/*
2494 				 *	Runtime library search path
2495 				 */
2496 				} else if (!strcmp(arg + 1, "rpath")) {
2497 					/* Aha, we should try to link both! */
2498 					cmd->install_path = argv[++a];
2499 					arg_used = 1;
2500 
2501 				} else if (!strcmp(arg + 1, "release")) {
2502 					/* Store for later deciphering */
2503 					cmd->version_info = argv[++a];
2504 					arg_used = 1;
2505 
2506 				} else if (!strcmp(arg + 1, "version-info")) {
2507 					/* Store for later deciphering */
2508 					cmd->version_info = argv[++a];
2509 					arg_used = 1;
2510 
2511 				} else if (!strcmp(arg + 1,
2512 						   "export-symbols-regex")) {
2513 					/* Skip the argument. */
2514 					++a;
2515 					arg_used = 1;
2516 
2517 				} else if (!strcmp(arg + 1, "undefined")) {
2518 					cmd->undefined_flag = argv[++a];
2519 					arg_used = 1;
2520 				/*
2521 				 *	Add dir to runtime library search path.
2522 				 */
2523 				} else if ((arg[1] == 'R') && !arg[2]) {
2524 
2525 					add_runtime_dir_lib(argv[++a], cmd);
2526 					arg_used = 1;
2527 				}
2528 			}
2529 		/*
2530 		 *	Ok.. the argument doesn't begin with a dash
2531 		 *	maybe it's an input file.
2532 		 *
2533 		 *	Check its extension to see if it's a known input
2534 		 *	file and verify it exists.
2535 		 */
2536 		} else {
2537 			arg_used = parse_input_file_name(arg, cmd);
2538 		}
2539 
2540 		/*
2541 		 *	If we still don't have a run mode, look for a magic
2542 		 *	program name CC, LINK, or whatever.  Then replace that
2543 		 *	with the name of the real program we want to run.
2544 		 */
2545 		if (!arg_used) {
2546 			if ((cmd->arglist->num == 0) &&
2547 				(cmd->mode == MODE_UNKNOWN)) {
2548 				arg = automode(arg, cmd);
2549 			}
2550 
2551 			DEBUG("Adding: %s\n", arg);
2552 
2553 			push_count_chars(cmd->arglist, arg);
2554 		}
2555 	}
2556 
2557 }
2558 
2559 int main(int argc, char *argv[])
2560 {
2561 	int rc;
2562 	command_t cmd;
2563 
2564 	memset(&cmd, 0, sizeof(cmd));
2565 
2566 	cmd.options.pic_mode = PIC_UNKNOWN;
2567 	cmd.mode = MODE_UNKNOWN;
2568 	cmd.output = OUT_GENERAL;
2569 
2570 	/*
2571 	 *	Initialise the various argument lists
2572 	 */
2573 	cmd.program_opts		= alloc_countchars();
2574 	cmd.arglist			= alloc_countchars();
2575 	cmd.tmp_dirs 			= alloc_countchars();
2576 	cmd.obj_files			= alloc_countchars();
2577 	cmd.dep_rpaths 			= alloc_countchars();
2578 	cmd.rpaths			= alloc_countchars();
2579 	cmd.static_opts.normal		= alloc_countchars();
2580 	cmd.shared_opts.normal		= alloc_countchars();
2581 	cmd.shared_opts.dependencies	= alloc_countchars();
2582 
2583 	/*
2584 	 *	Fill up the various argument lists
2585 	 */
2586 	parse_args(argc, argv, &cmd);
2587 	post_parse_fixup(&cmd);
2588 
2589 	/*
2590 	 *	We couldn't figure out which mode to operate in
2591 	 */
2592 	if (cmd.mode == MODE_UNKNOWN) {
2593 		usage(1);
2594 	}
2595 
2596 	rc = run_mode(&cmd);
2597 	if (!rc) {
2598 		add_for_runtime(&cmd);
2599 	}
2600 
2601 	cleanup_tmp_dirs(&cmd);
2602 
2603 	return rc;
2604 }
2605