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 ) {
220 if (strcmp(arg, "no-install") == 0) {
229 bool parse_input_file_name(char *arg, cmd_data_t *cmd_data)
231 char *ext = strrchr(arg, '.');
232 char *name = strrchr(arg, '/');
242 name = strrchr(arg, '\\');
253 if (strcmp(ext, "lo") == 0) {
254 newarg = (char *)malloc(strlen(arg) + 10);
256 strcpy(newarg + (ext - arg), OBJECT_EXT);
257 cmd_data->arglist[cmd_data->num_args++] = newarg;
258 cmd_data->obj_files[cmd_data->num_obj_files++] = newarg;
262 if (strcmp(ext, "la") == 0) {
263 newarg = (char *)malloc(strlen(arg) + 10);
266 strcat(newarg, ".libs/");
268 if (strncmp(name, "lib", 3) == 0) {
272 strcat(newarg, name);
273 ext = strrchr(newarg, '.') + 1;
275 if (shared && cmd_data->mode == mInstall) {
276 strcpy(ext, DYNAMIC_LIB_EXT);
277 newarg = truncate_dll_name(newarg);
279 strcpy(ext, STATIC_LIB_EXT);
282 cmd_data->arglist[cmd_data->num_args++] = newarg;
286 if (strcmp(ext, "c") == 0) {
287 if (cmd_data->stub_name == NULL) {
288 cmd_data->stub_name = (char *)malloc(strlen(arg) + 4);
289 strcpy(cmd_data->stub_name, arg);
290 strcpy(strrchr(cmd_data->stub_name, '.') + 1, "lo");
294 if (strcmp(name, CC) == 0 || strcmp(name, CC EXE_EXT) == 0) {
295 if (cmd_data->output_type == otGeneral) {
296 cmd_data->output_type = otObject;
305 bool parse_output_file_name(char *arg, cmd_data_t *cmd_data)
307 char *name = strrchr(arg, '/');
308 char *ext = strrchr(arg, '.');
309 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;
336 if (strcmp(ext, "la") == 0) {
337 cmd_data->stub_name = arg;
338 cmd_data->output_type = shared ? otDynamicLibrary : otStaticLibrary;
339 newarg = (char *)malloc(strlen(arg) + 10);
341 strcpy(newarg, ".libs/");
343 if (strncmp(arg, "lib", 3) == 0) {
348 newext = strrchr(newarg, '.') + 1;
349 strcpy(newext, shared ? DYNAMIC_LIB_EXT : STATIC_LIB_EXT);
351 #ifdef TRUNCATE_DLL_NAME
353 newarg = truncate_dll_name(newarg);
357 cmd_data->arglist[cmd_data->num_args++] = newarg;
358 cmd_data->output_name = newarg;
362 if (strcmp(ext, "lo") == 0) {
363 cmd_data->stub_name = arg;
364 cmd_data->output_type = otObject;
365 newarg = (char *)malloc(strlen(arg) + 2);
367 ext = strrchr(newarg, '.') + 1;
368 strcpy(ext, OBJECT_EXT);
369 cmd_data->arglist[cmd_data->num_args++] = newarg;
370 cmd_data->output_name = newarg;
379 void post_parse_fixup(cmd_data_t *cmd_data)
385 if (cmd_data->output_type == otStaticLibrary && cmd_data->mode == mLink) {
386 /* We do a real hatchet job on the args when making a static library
387 * removing all compiler switches & any other cruft that ar won't like
388 * We also need to explode any libraries listed
391 for (a=0; a < cmd_data->num_args; a++) {
392 arg = cmd_data->arglist[a];
395 ext = strrchr(arg, '.');
402 cmd_data->arglist[a] = NULL;
404 if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) {
405 cmd_data->arglist[a+1] = NULL;
408 if (strcmp(arg, "-R") == 0 && a+1 < cmd_data->num_args) {
409 cmd_data->arglist[a+1] = NULL;
412 if (strcmp(arg, "-version-info") == 0 && a+1 < cmd_data->num_args) {
413 cmd_data->arglist[a+1] = NULL;
416 if (strcmp(arg, "-Zstack") == 0 && a+1 < cmd_data->num_args) {
417 cmd_data->arglist[a+1] = NULL;
420 if (strcmp(arg, "-o") == 0) {
425 if (strcmp(arg, CC) == 0 || strcmp(arg, CC EXE_EXT) == 0) {
426 cmd_data->arglist[a] = LIBRARIAN " cr";
430 if (strcmp(ext, "h") == 0 || strcmp(ext, "c") == 0) {
431 /* ignore source files, they don't belong in a library */
432 cmd_data->arglist[a] = NULL;
435 if (strcmp(ext, STATIC_LIB_EXT) == 0) {
436 cmd_data->arglist[a] = NULL;
437 explode_static_lib(arg, cmd_data);
444 if (cmd_data->output_type == otDynamicLibrary) {
445 for (a=0; a < cmd_data->num_args; a++) {
446 arg = cmd_data->arglist[a];
449 if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) {
450 cmd_data->arglist[a] = NULL;
451 cmd_data->arglist[a+1] = NULL;
457 generate_def_file(cmd_data);
462 if (cmd_data->output_type == otObject ||
463 cmd_data->output_type == otProgram ||
464 cmd_data->output_type == otDynamicLibrary) {
465 cmd_data->arglist[cmd_data->num_args++] = "-Zomf";
469 if (shared && (cmd_data->output_type == otObject || cmd_data->output_type == otDynamicLibrary)) {
470 cmd_data->arglist[cmd_data->num_args++] = SHARE_SW;
476 int execute_command(cmd_data_t *cmd_data)
480 int a, total_len = 0;
483 for (a=0; a < cmd_data->num_args; a++) {
484 if (cmd_data->arglist[a]) {
485 total_len += strlen(cmd_data->arglist[a]) + 1;
489 command = (char *)malloc( total_len );
492 for (a=0; a < cmd_data->num_args; a++) {
493 if (cmd_data->arglist[a]) {
494 strcat(command, cmd_data->arglist[a]);
495 strcat(command, " ");
499 command[strlen(command)-1] = 0;
505 cmd_data->num_args = target;
506 cmd_data->arglist[cmd_data->num_args] = NULL;
507 command = shell_esc(command);
513 return spawnvp(P_WAIT, args[0], args);
518 char *shell_esc(const char *str)
522 const unsigned char *s;
524 cmd = (char *)malloc(2 * strlen(str) + 1);
525 d = (unsigned char *)cmd;
526 s = (const unsigned char *)str;
529 if (*s == '"' || *s == '\\') {
541 bool explode_static_lib(char *lib, cmd_data_t *cmd_data)
548 struct dirent *entry;
551 strcat(tmpdir, ".exploded");
554 cmd_data->tmp_dirs[cmd_data->num_tmp_dirs++] = strdup(tmpdir);
555 getcwd(savewd, sizeof(savewd));
557 if (chdir(tmpdir) != 0)
560 strcpy(cmd, LIBRARIAN " x ");
561 name = strrchr(lib, '/');
573 dir = opendir(tmpdir);
575 while ((entry = readdir(dir)) != NULL) {
576 if (entry->d_name[0] != '.') {
579 strcat(cmd, entry->d_name);
580 cmd_data->arglist[cmd_data->num_args++] = strdup(cmd);
590 void cleanup_tmp_dir(char *dirname)
593 struct dirent *entry;
596 dir = opendir(dirname);
601 while ((entry = readdir(dir)) != NULL) {
602 if (entry->d_name[0] != '.') {
603 strcpy(fullname, dirname);
604 strcat(fullname, "/");
605 strcat(fullname, entry->d_name);
615 void cleanup_tmp_dirs(cmd_data_t *cmd_data)
619 for (d=0; d < cmd_data->num_tmp_dirs; d++) {
620 cleanup_tmp_dir(cmd_data->tmp_dirs[d]);
626 void generate_def_file(cmd_data_t *cmd_data)
629 char implib_file[1024];
632 char *export_args[1024];
633 int num_export_args = 0;
638 if (cmd_data->output_name) {
639 strcpy(def_file, cmd_data->output_name);
640 strcat(def_file, ".def");
641 hDef = fopen(def_file, "w");
644 fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name));
645 fprintf(hDef, "DATA NONSHARED\n");
646 fprintf(hDef, "EXPORTS\n");
649 for (a=0; a < cmd_data->num_obj_files; a++) {
650 cmd_size += strlen(cmd_data->obj_files[a]) + 1;
653 cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3;
654 cmd = (char *)malloc(cmd_size);
655 strcpy(cmd, GEN_EXPORTS);
657 for (a=0; a < cmd_data->num_obj_files; a++) {
659 strcat(cmd, cmd_data->obj_files[a] );
663 strcat(cmd, def_file);
665 export_args[num_export_args++] = SHELL_CMD;
666 export_args[num_export_args++] = "-c";
667 export_args[num_export_args++] = cmd;
668 export_args[num_export_args++] = NULL;
669 spawnvp(P_WAIT, export_args[0], export_args);
670 cmd_data->arglist[cmd_data->num_args++] = strdup(def_file);
672 /* Now make an import library for the dll */
674 export_args[num_export_args++] = DEF2IMPLIB_CMD;
675 export_args[num_export_args++] = "-o";
677 strcpy(implib_file, ".libs/");
678 strcat(implib_file, cmd_data->stub_name);
679 ext = strrchr(implib_file, '.');
684 strcat(implib_file, ".");
685 strcat(implib_file, STATIC_LIB_EXT);
687 export_args[num_export_args++] = implib_file;
688 export_args[num_export_args++] = def_file;
689 export_args[num_export_args++] = NULL;
690 spawnvp(P_WAIT, export_args[0], export_args);
697 /* returns just a file's name without path or extension */
698 char *nameof(char *fullpath)
702 char *name = strrchr(fullpath, '/');
705 name = strrchr(fullpath, '\\');
714 strcpy(buffer, name);
715 ext = strrchr(buffer, '.');
719 return strdup(buffer);
727 char *truncate_dll_name(char *path)
729 /* Cut DLL name down to 8 characters after removing any mod_ prefix */
730 char *tmppath = strdup(path);
731 char *newname = strrchr(tmppath, '/') + 1;
732 char *ext = strrchr(tmppath, '.');
740 if (strncmp(newname, "mod_", 4) == 0) {
741 strcpy(newname, newname + 4);
746 strcpy(newname + 8, strchr(newname, '.'));