2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <sys/types.h>
19 #include <vppinfra/bitmap.h>
20 #include <vppinfra/format.h>
21 #include <vppinfra/hash.h>
23 #define foreach_libtool_mode _ (compile) _ (link) _ (install)
26 #define _(m) MODE_##m,
54 lt_edit_type_t output_edit_type;
57 lt_lib_path_t * lib_path;
62 static lt_lib_path_t *
63 search_lib_path (lt_main_t * lm, char * fmt, ...)
66 static u8 * file_name, * path_name;
67 lt_lib_path_t * p = 0;
70 _vec_len (file_name) = 0;
73 file_name = va_format (file_name, fmt, &va);
77 vec_foreach (p, lm->lib_path)
82 _vec_len (path_name) = 0;
84 path_name = format (path_name, "%s/%v%c", p->path, file_name, 0);
85 if (stat ((char *) path_name, &st) >= 0)
91 static u8 * format_libtool_mode (u8 * s, va_list * args)
93 int m = va_arg (*args, int);
97 #define _(f) case MODE_##f: t = #f; break;
104 vec_add (s, t, strlen (t));
106 s = format (s, "unknown 0x%x", m);
110 static uword unformat_libtool_mode (unformat_input_t * input, va_list * args)
112 int * result = va_arg (*args, int *);
113 #define _(m) if (unformat (input, #m)) { *result = MODE_##m; return 1; }
114 foreach_libtool_mode;
119 static uword unformat_basename (unformat_input_t * input, va_list * args)
121 u8 ** result = va_arg (*args, u8 **);
122 u8 * suffix = va_arg (*args, u8 *);
123 u8 * current_suffix = suffix;
126 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
138 vec_add1 (*result, c);
139 if (c == *current_suffix)
142 current_suffix = suffix;
144 if (*current_suffix == 0)
146 _vec_len (*result) -= current_suffix - suffix;
155 static void edit (lt_main_t * lm, lt_edit_type_t type, char * fmt, ...)
162 s = va_format (0, fmt, &va);
165 vec_add2 (lm->edits, e, 1);
170 static u8 * format_argv (u8 * s, va_list * args)
172 u8 ** a = va_arg (*args, u8 **);
174 for (i = 0; i < vec_len (a) - 1; i++)
178 vec_add (s, a[i], vec_len (a[i]) - 1);
183 static u8 * format_dirname (u8 * s, va_list * args)
185 u8 * f = va_arg (*args, u8 *);
188 for (t = vec_end (f) - 1; t >= f; t--)
194 vec_add (s, f, t - f);
200 static u8 * format_basename (u8 * s, va_list * args)
202 u8 * f = va_arg (*args, u8 *);
205 for (t = vec_end (f) - 1; t >= f; t--)
211 vec_add (s, t + 1, vec_end (f) - (t + 1));
213 vec_add (s, f, vec_len (f));
217 static void my_system (char * fmt, ...)
223 s = va_format (0, fmt, &va);
226 vec_add1 (s, 0); /* null terminate */
227 if (system ((char *) s) != 0)
228 clib_error ("%s", s);
232 static u8 * my_cmd (char * fmt, ...)
240 s = va_format (0, fmt, &va);
243 vec_add1 (s, 0); /* null terminate */
244 result = popen ((char *) s, "r");
246 clib_error ("%s", s);
248 while ((c = fgetc (result)) != EOF)
254 static void make_file_with_contents (lt_main_t * lm, u8 * contents, char * fmt, ...)
261 s = va_format (0, fmt, &va);
264 vec_add1 (s, 0); /* null terminate */
265 f = fopen ((char *) s, "w");
268 clib_error ("fopen %s", s);
270 if (1 != fwrite (contents, vec_len (contents), 1, f))
271 clib_error ("fwrite");
276 static u8 ** add_argv (u8 ** argv, char * fmt, ...)
282 s = va_format (0, fmt, &va);
284 vec_add1 (s, 0); /* null terminate */
289 #define GEN_ARGV_PIC (1 << 0)
290 #define GEN_ARGV_PUNT (1 << 1)
292 static u8 ** gen_argv (lt_main_t * lm, uword flags)
295 uword * path_used_bitmap = 0;
299 is_punt = (flags & GEN_ARGV_PUNT) != 0;
302 /* No supported so punt back to shell based libtool. */
303 r = add_argv (r, "/bin/sh");
304 r = add_argv (r, "./libtool");
305 r = add_argv (r, "--mode=%U", format_libtool_mode, lm->mode);
308 if (lm->mode == MODE_compile)
309 ASSERT (lm->output_edit_type != OUTPUT_LA);
311 vec_foreach (e, lm->edits)
316 r = add_argv (r, "%v", e->data);
321 my_system ("mkdir -p %U/.libs", format_dirname, e->data);
322 r = add_argv (r, "-o");
323 r = add_argv (r, "%s%v", is_punt ? "" : ".libs/", e->data);
327 if (flags & GEN_ARGV_PIC)
329 r = add_argv (r, "-fPIC");
330 r = add_argv (r, "-DPIC");
332 r = add_argv (r, "-o");
335 r = add_argv (r, "-o %v.lo", e->data);
337 else if (flags & GEN_ARGV_PIC)
339 my_system ("mkdir -p %U/.libs", format_dirname, e->data);
340 r = add_argv (r, "%U/.libs/%U.o",
341 format_dirname, e->data,
342 format_basename, e->data);
346 my_system ("mkdir -p %U", format_dirname, e->data);
347 r = add_argv (r, "%v.o", e->data);
353 r = add_argv (r, "-o %v.la", e->data);
360 r = add_argv (r, "%v.la", e->data);
362 else if (lm->mode == MODE_link)
364 u8 * pwd = get_current_dir_name ();
365 u8 * libdir = my_cmd (". %s/%v.la && echo -n ${libdir}", pwd, e->data);
367 if (! hash_get_mem (lm->rpath_hash, libdir))
369 r = add_argv (r, "-Wl,-rpath");
370 r = add_argv (r, "-Wl,%v", libdir);
371 hash_set_mem (lm->rpath_hash, libdir, 0);
374 r = add_argv (r, "%U/.libs/%U.so",
375 format_dirname, e->data,
376 format_basename, e->data);
379 r = add_argv (r, "%v.la", e->data);
383 if (lm->mode == MODE_link && ! is_punt)
385 lt_lib_path_t * p = search_lib_path (lm, "lib%v.so", e->data);
388 path_used_bitmap = clib_bitmap_ori (path_used_bitmap, p - lm->lib_path);
389 r = add_argv (r, "%s/lib%v.so", p->path, e->data);
392 r = add_argv (r, "-l%v", e->data);
396 r = add_argv (r, "-l%v", e->data);
406 clib_bitmap_foreach (i, path_used_bitmap, ({
407 lt_lib_path_t * p = vec_elt_at_index (lm->lib_path, i);
408 r = add_argv (r, "-Wl,-rpath");
409 r = add_argv (r, "-Wl,%s", p->path);
411 clib_bitmap_free (path_used_bitmap);
419 static void do_command (lt_main_t * lm, u8 ** argv)
421 u8 * cmd = format (0, "%U%c", format_argv, argv, 0);
424 fformat (stderr, "lt: %s\n", cmd);
426 if (system ((char *) cmd))
432 static int lt_main (unformat_input_t * input)
434 lt_main_t _lm = {0}, * lm = &_lm;
435 clib_error_t * error = 0;
438 lm->rpath_hash = hash_create_vec (0, sizeof (u8), sizeof (uword));
439 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
446 if (unformat (input, "-o %s", &s))
448 u8 * dot = vec_end (s) - 4;
449 int is_la = 0, is_lo = 0;
451 is_lo = vec_len (s) >= 4 && ! strcmp ((char *) dot, ".lo");
452 is_la = vec_len (s) >= 4 && ! strcmp ((char *) dot, ".la");
456 lm->output_edit_type = is_lo ? OUTPUT_LO : OUTPUT_LA;
459 lm->output_edit_type = OUTPUT_EXE;
460 edit (lm, lm->output_edit_type, "%s", s);
461 lm->output_file = format (0, "%s", s);
464 else if (unformat (input, "-L%s", &s))
467 vec_add2 (lm->lib_path, p, 1);
469 edit (lm, LITERAL, "-L%s", s);
472 else if (unformat (input, "%U", unformat_basename, &s, ".la"))
473 edit (lm, LT_LIB, "%v", s);
475 else if (unformat (input, "-l%s", &s))
476 edit (lm, NON_LT_LIB, "%s", s);
478 else if (unformat (input, "--mode=%U", unformat_libtool_mode, &lm->mode))
481 else if (unformat (input, "--tag=%s", &lm->tag))
484 else if (unformat (input, "-static"))
487 edit (lm, LITERAL, "%s", "-static");
490 else if (unformat (input, "%s", &s))
491 edit (lm, LITERAL, "%s", s);
495 error = clib_error_create ("parse error `%U'",
496 format_unformat_error, input);
504 if (! (lm->mode == MODE_compile
505 || (lm->mode == MODE_link && lm->output_edit_type == OUTPUT_EXE && ! lm->link_static)))
507 argv = gen_argv (lm, GEN_ARGV_PUNT);
508 do_command (lm, argv);
510 else if (lm->mode == MODE_compile)
512 argv = gen_argv (lm, GEN_ARGV_PIC);
513 do_command (lm, argv);
514 argv = gen_argv (lm, 0);
515 do_command (lm, argv);
519 argv = gen_argv (lm, 0);
520 do_command (lm, argv);
523 if (lm->mode == MODE_compile)
526 u8 * f = lm->output_file;
528 /* Need this or .lo files are rejected. */
529 s = format (s, "# Generated by libtool (Eliot lt 0.0)\n");
531 s = format (s, "pic_object='.libs/%U.o'\n", format_basename, f);
532 s = format (s, "non_pic_object='%U.o'\n", format_basename, f);
533 make_file_with_contents (lm, s, "%v.lo", f);
536 else if (lm->mode == MODE_link)
539 u8 * f = lm->output_file;
541 "# Generated by libtool (Eliot lt) 2.4\n"
542 "# %%%MAGIC variable%%%\n"
543 "generated_by_libtool_version=2.4\n");
544 make_file_with_contents (lm, s, "%v", f);
552 if (waitpid (-1, &status, 0) < 0 && errno == ECHILD)
564 clib_error_report (error);
570 int main (int argc, char * argv[])
574 unformat_init_command_line (&i, argv);