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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <sys/types.h>
30 bool export_all = false;
31 enum mode_t { mCompile, mLink, mInstall };
32 enum output_type_t { otGeneral, otObject, otProgram, otStaticLibrary, otDynamicLibrary };
35 # define SHELL_CMD "sh"
37 # define GEN_EXPORTS "emxexp"
38 # define DEF2IMPLIB_CMD "emximp"
39 # define SHARE_SW "-Zdll -Zmtd"
41 # define TRUNCATE_DLL_NAME
42 # define DYNAMIC_LIB_EXT "dll"
43 # define EXE_EXT ".exe"
46 /* OMF is the native format under OS/2 */
47 # define STATIC_LIB_EXT "lib"
48 # define OBJECT_EXT "obj"
49 # define LIBRARIAN "emxomfar"
51 /* but the alternative, a.out, can fork() which is sometimes necessary */
52 # define STATIC_LIB_EXT "a"
53 # define OBJECT_EXT "o"
54 # define LIBRARIAN "ar"
63 enum output_type_t output_type;
68 char *obj_files[1024];
72 void parse_args(int argc, char *argv[], cmd_data_t *cmd_data);
73 bool parse_long_opt(char *arg, cmd_data_t *cmd_data);
74 int parse_short_opt(char *arg, cmd_data_t *cmd_data);
75 bool parse_input_file_name(char *arg, cmd_data_t *cmd_data);
76 bool parse_output_file_name(char *arg, cmd_data_t *cmd_data);
77 void post_parse_fixup(cmd_data_t *cmd_data);
78 bool explode_static_lib(char *lib, cmd_data_t *cmd_data);
79 int execute_command(cmd_data_t *cmd_data);
80 char *shell_esc(const char *str);
81 void cleanup_tmp_dirs(cmd_data_t *cmd_data);
82 void generate_def_file(cmd_data_t *cmd_data);
83 char *nameof(char *fullpath);
84 char *truncate_dll_name(char *path);
87 int main(int argc, char *argv[])
92 memset(&cmd_data, 0, sizeof(cmd_data));
93 cmd_data.mode = mCompile;
94 cmd_data.output_type = otGeneral;
96 parse_args(argc, argv, &cmd_data);
97 rc = execute_command(&cmd_data);
99 if (rc == 0 && cmd_data.stub_name) {
100 fopen(cmd_data.stub_name, "w");
103 cleanup_tmp_dirs(&cmd_data);
109 void parse_args(int argc, char *argv[], cmd_data_t *cmd_data)
115 for (a=1; a < argc; a++) {
121 argused = parse_long_opt(arg + 2, cmd_data);
122 } else if (arg[1] == 'o' && a+1 < argc) {
123 cmd_data->arglist[cmd_data->num_args++] = arg;
125 argused = parse_output_file_name(arg, cmd_data);
127 int num_used = parse_short_opt(arg + 1, cmd_data);
128 argused = num_used > 0;
135 argused = parse_input_file_name(arg, cmd_data);
139 cmd_data->arglist[cmd_data->num_args++] = arg;
143 post_parse_fixup(cmd_data);
148 bool parse_long_opt(char *arg, cmd_data_t *cmd_data)
150 char *equal_pos = strchr(arg, '=');
155 strncpy(var, arg, equal_pos - arg);
156 var[equal_pos - arg] = 0;
157 strcpy(value, equal_pos + 1);
162 if (strcmp(var, "silent") == 0) {
164 } else if (strcmp(var, "mode") == 0) {
165 if (strcmp(value, "compile") == 0) {
166 cmd_data->mode = mCompile;
167 cmd_data->output_type = otObject;
170 if (strcmp(value, "link") == 0) {
171 cmd_data->mode = mLink;
174 if (strcmp(value, "install") == 0) {
175 cmd_data->mode = mInstall;
177 } else if (strcmp(var, "shared") == 0) {
179 } else if (strcmp(var, "export-all") == 0) {
190 int parse_short_opt(char *arg, cmd_data_t *cmd_data)
192 if (strcmp(arg, "export-dynamic") == 0) {
196 if (strcmp(arg, "module") == 0) {
200 if (strcmp(arg, "Zexe") == 0) {
204 if (strcmp(arg, "avoid-version") == 0) {
208 if (strcmp(arg, "prefer-pic") == 0) {
212 if (strcmp(arg, "prefer-non-pic") == 0) {
216 if (strcmp(arg, "version-info") == 0 ) {
225 bool parse_input_file_name(char *arg, cmd_data_t *cmd_data)
227 char *ext = strrchr(arg, '.');
228 char *name = strrchr(arg, '/');
239 name = strrchr(arg, '\\');
250 pathlen = name - arg;
252 if (strcmp(ext, "lo") == 0) {
253 newarg = (char *)malloc(strlen(arg) + 10);
255 strcpy(newarg + (ext - arg), OBJECT_EXT);
256 cmd_data->arglist[cmd_data->num_args++] = newarg;
257 cmd_data->obj_files[cmd_data->num_obj_files++] = newarg;
261 if (strcmp(ext, "la") == 0) {
262 newarg = (char *)malloc(strlen(arg) + 10);
265 strcat(newarg, ".libs/");
267 if (strncmp(name, "lib", 3) == 0) {
271 strcat(newarg, name);
272 ext = strrchr(newarg, '.') + 1;
274 if (shared && cmd_data->mode == mInstall) {
275 strcpy(ext, DYNAMIC_LIB_EXT);
276 newarg = truncate_dll_name(newarg);
278 strcpy(ext, STATIC_LIB_EXT);
281 cmd_data->arglist[cmd_data->num_args++] = newarg;
285 if (strcmp(ext, "c") == 0) {
286 if (cmd_data->stub_name == NULL) {
287 cmd_data->stub_name = (char *)malloc(strlen(arg) + 4);
288 strcpy(cmd_data->stub_name, arg);
289 strcpy(strrchr(cmd_data->stub_name, '.') + 1, "lo");
293 if (strcmp(name, CC) == 0 || strcmp(name, CC EXE_EXT) == 0) {
294 if (cmd_data->output_type == otGeneral) {
295 cmd_data->output_type = otObject;
304 bool parse_output_file_name(char *arg, cmd_data_t *cmd_data)
306 char *name = strrchr(arg, '/');
307 char *ext = strrchr(arg, '.');
308 char *newarg = NULL, *newext;
312 name = strrchr(arg, '\\');
324 cmd_data->stub_name = arg;
325 cmd_data->output_type = otProgram;
326 newarg = (char *)malloc(strlen(arg) + 5);
328 strcat(newarg, EXE_EXT);
329 cmd_data->arglist[cmd_data->num_args++] = newarg;
330 cmd_data->output_name = newarg;
335 pathlen = name - arg;
337 if (strcmp(ext, "la") == 0) {
338 cmd_data->stub_name = arg;
339 cmd_data->output_type = shared ? otDynamicLibrary : otStaticLibrary;
340 newarg = (char *)malloc(strlen(arg) + 10);
342 strcpy(newarg, ".libs/");
344 if (strncmp(arg, "lib", 3) == 0) {
349 newext = strrchr(newarg, '.') + 1;
350 strcpy(newext, shared ? DYNAMIC_LIB_EXT : STATIC_LIB_EXT);
352 #ifdef TRUNCATE_DLL_NAME
354 newarg = truncate_dll_name(newarg);
358 cmd_data->arglist[cmd_data->num_args++] = newarg;
359 cmd_data->output_name = newarg;
363 if (strcmp(ext, "lo") == 0) {
364 cmd_data->stub_name = arg;
365 cmd_data->output_type = otObject;
366 newarg = (char *)malloc(strlen(arg) + 2);
368 ext = strrchr(newarg, '.') + 1;
369 strcpy(ext, OBJECT_EXT);
370 cmd_data->arglist[cmd_data->num_args++] = newarg;
371 cmd_data->output_name = newarg;
380 void post_parse_fixup(cmd_data_t *cmd_data)
386 if (cmd_data->output_type == otStaticLibrary && cmd_data->mode == mLink) {
387 /* We do a real hatchet job on the args when making a static library
388 * removing all compiler switches & any other cruft that ar won't like
389 * We also need to explode any libraries listed
392 for (a=0; a < cmd_data->num_args; a++) {
393 arg = cmd_data->arglist[a];
396 ext = strrchr(arg, '.');
403 cmd_data->arglist[a] = NULL;
405 if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) {
406 cmd_data->arglist[a+1] = NULL;
409 if (strcmp(arg, "-R") == 0 && a+1 < cmd_data->num_args) {
410 cmd_data->arglist[a+1] = NULL;
413 if (strcmp(arg, "-version-info") == 0 && a+1 < cmd_data->num_args) {
414 cmd_data->arglist[a+1] = NULL;
417 if (strcmp(arg, "-Zstack") == 0 && a+1 < cmd_data->num_args) {
418 cmd_data->arglist[a+1] = NULL;
421 if (strcmp(arg, "-o") == 0) {
426 if (strcmp(arg, CC) == 0 || strcmp(arg, CC EXE_EXT) == 0) {
427 cmd_data->arglist[a] = LIBRARIAN " cr";
431 if (strcmp(ext, "h") == 0 || strcmp(ext, "c") == 0) {
432 /* ignore source files, they don't belong in a library */
433 cmd_data->arglist[a] = NULL;
436 if (strcmp(ext, STATIC_LIB_EXT) == 0) {
437 cmd_data->arglist[a] = NULL;
438 explode_static_lib(arg, cmd_data);
445 if (cmd_data->output_type == otDynamicLibrary) {
446 for (a=0; a < cmd_data->num_args; a++) {
447 arg = cmd_data->arglist[a];
450 if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) {
451 cmd_data->arglist[a] = NULL;
452 cmd_data->arglist[a+1] = NULL;
458 generate_def_file(cmd_data);
463 if (cmd_data->output_type == otObject ||
464 cmd_data->output_type == otProgram ||
465 cmd_data->output_type == otDynamicLibrary) {
466 cmd_data->arglist[cmd_data->num_args++] = "-Zomf";
470 if (shared && (cmd_data->output_type == otObject || cmd_data->output_type == otDynamicLibrary)) {
471 cmd_data->arglist[cmd_data->num_args++] = SHARE_SW;
477 int execute_command(cmd_data_t *cmd_data)
481 int a, total_len = 0;
484 for (a=0; a < cmd_data->num_args; a++) {
485 if (cmd_data->arglist[a]) {
486 total_len += strlen(cmd_data->arglist[a]) + 1;
490 command = (char *)malloc( total_len );
493 for (a=0; a < cmd_data->num_args; a++) {
494 if (cmd_data->arglist[a]) {
495 strcat(command, cmd_data->arglist[a]);
496 strcat(command, " ");
500 command[strlen(command)-1] = 0;
506 cmd_data->num_args = target;
507 cmd_data->arglist[cmd_data->num_args] = NULL;
508 command = shell_esc(command);
514 return spawnvp(P_WAIT, args[0], args);
519 char *shell_esc(const char *str)
523 const unsigned char *s;
525 cmd = (char *)malloc(2 * strlen(str) + 1);
526 d = (unsigned char *)cmd;
527 s = (const unsigned char *)str;
530 if (*s == '"' || *s == '\\') {
542 bool explode_static_lib(char *lib, cmd_data_t *cmd_data)
549 struct dirent *entry;
552 strcat(tmpdir, ".exploded");
555 cmd_data->tmp_dirs[cmd_data->num_tmp_dirs++] = strdup(tmpdir);
556 getcwd(savewd, sizeof(savewd));
558 if (chdir(tmpdir) != 0)
561 strcpy(cmd, LIBRARIAN " x ");
562 name = strrchr(lib, '/');
574 dir = opendir(tmpdir);
576 while ((entry = readdir(dir)) != NULL) {
577 if (entry->d_name[0] != '.') {
580 strcat(cmd, entry->d_name);
581 cmd_data->arglist[cmd_data->num_args++] = strdup(cmd);
591 void cleanup_tmp_dir(char *dirname)
594 struct dirent *entry;
597 dir = opendir(dirname);
602 while ((entry = readdir(dir)) != NULL) {
603 if (entry->d_name[0] != '.') {
604 strcpy(fullname, dirname);
605 strcat(fullname, "/");
606 strcat(fullname, entry->d_name);
616 void cleanup_tmp_dirs(cmd_data_t *cmd_data)
620 for (d=0; d < cmd_data->num_tmp_dirs; d++) {
621 cleanup_tmp_dir(cmd_data->tmp_dirs[d]);
627 void generate_def_file(cmd_data_t *cmd_data)
630 char implib_file[1024];
633 char *export_args[1024];
634 int num_export_args = 0;
639 if (cmd_data->output_name) {
640 strcpy(def_file, cmd_data->output_name);
641 strcat(def_file, ".def");
642 hDef = fopen(def_file, "w");
645 fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name));
646 fprintf(hDef, "DATA NONSHARED\n");
647 fprintf(hDef, "EXPORTS\n");
650 for (a=0; a < cmd_data->num_obj_files; a++) {
651 cmd_size += strlen(cmd_data->obj_files[a]) + 1;
654 cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3;
655 cmd = (char *)malloc(cmd_size);
656 strcpy(cmd, GEN_EXPORTS);
658 for (a=0; a < cmd_data->num_obj_files; a++) {
660 strcat(cmd, cmd_data->obj_files[a] );
664 strcat(cmd, def_file);
666 export_args[num_export_args++] = SHELL_CMD;
667 export_args[num_export_args++] = "-c";
668 export_args[num_export_args++] = cmd;
669 export_args[num_export_args++] = NULL;
670 spawnvp(P_WAIT, export_args[0], export_args);
671 cmd_data->arglist[cmd_data->num_args++] = strdup(def_file);
673 /* Now make an import library for the dll */
675 export_args[num_export_args++] = DEF2IMPLIB_CMD;
676 export_args[num_export_args++] = "-o";
678 strcpy(implib_file, ".libs/");
679 strcat(implib_file, cmd_data->stub_name);
680 ext = strrchr(implib_file, '.');
685 strcat(implib_file, ".");
686 strcat(implib_file, STATIC_LIB_EXT);
688 export_args[num_export_args++] = implib_file;
689 export_args[num_export_args++] = def_file;
690 export_args[num_export_args++] = NULL;
691 spawnvp(P_WAIT, export_args[0], export_args);
698 /* returns just a file's name without path or extension */
699 char *nameof(char *fullpath)
703 char *name = strrchr(fullpath, '/');
706 name = strrchr(fullpath, '\\');
715 strcpy(buffer, name);
716 ext = strrchr(buffer, '.');
720 return strdup(buffer);
728 char *truncate_dll_name(char *path)
730 /* Cut DLL name down to 8 characters after removing any mod_ prefix */
731 char *tmppath = strdup(path);
732 char *newname = strrchr(tmppath, '/') + 1;
733 char *ext = strrchr(tmppath, '.');
741 if (strncmp(newname, "mod_", 4) == 0) {
742 strcpy(newname, newname + 4);
747 strcpy(newname + 8, strchr(newname, '.'));