aplibtool.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  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. #include <stdio.h>
  17. #include <process.h>
  18. #include <string.h>
  19. #include <stdlib.h>
  20. #include <sys/types.h>
  21. #include <dirent.h>
  22. typedef char bool;
  23. #define false 0
  24. #define true (!false)
  25. bool silent = false;
  26. bool shared = false;
  27. bool export_all = false;
  28. enum mode_t { mCompile, mLink, mInstall };
  29. enum output_type_t { otGeneral, otObject, otProgram, otStaticLibrary, otDynamicLibrary };
  30. #ifdef __EMX__
  31. # define SHELL_CMD "sh"
  32. # define CC "gcc"
  33. # define GEN_EXPORTS "emxexp"
  34. # define DEF2IMPLIB_CMD "emximp"
  35. # define SHARE_SW "-Zdll -Zmtd"
  36. # define USE_OMF true
  37. # define TRUNCATE_DLL_NAME
  38. # define DYNAMIC_LIB_EXT "dll"
  39. # define EXE_EXT ".exe"
  40. # if USE_OMF
  41. /* OMF is the native format under OS/2 */
  42. # define STATIC_LIB_EXT "lib"
  43. # define OBJECT_EXT "obj"
  44. # define LIBRARIAN "emxomfar"
  45. # else
  46. /* but the alternative, a.out, can fork() which is sometimes necessary */
  47. # define STATIC_LIB_EXT "a"
  48. # define OBJECT_EXT "o"
  49. # define LIBRARIAN "ar"
  50. # endif
  51. #endif
  52. typedef struct {
  53. char *arglist[1024];
  54. int num_args;
  55. enum mode_t mode;
  56. enum output_type_t output_type;
  57. char *output_name;
  58. char *stub_name;
  59. char *tmp_dirs[1024];
  60. int num_tmp_dirs;
  61. char *obj_files[1024];
  62. int num_obj_files;
  63. } cmd_data_t;
  64. void parse_args(int argc, char *argv[], cmd_data_t *cmd_data);
  65. bool parse_long_opt(char *arg, cmd_data_t *cmd_data);
  66. int parse_short_opt(char *arg, cmd_data_t *cmd_data);
  67. bool parse_input_file_name(char *arg, cmd_data_t *cmd_data);
  68. bool parse_output_file_name(char *arg, cmd_data_t *cmd_data);
  69. void post_parse_fixup(cmd_data_t *cmd_data);
  70. bool explode_static_lib(char *lib, cmd_data_t *cmd_data);
  71. int execute_command(cmd_data_t *cmd_data);
  72. char *shell_esc(const char *str);
  73. void cleanup_tmp_dirs(cmd_data_t *cmd_data);
  74. void generate_def_file(cmd_data_t *cmd_data);
  75. char *nameof(char *fullpath);
  76. char *truncate_dll_name(char *path);
  77. int main(int argc, char *argv[])
  78. {
  79. int rc;
  80. cmd_data_t cmd_data;
  81. memset(&cmd_data, 0, sizeof(cmd_data));
  82. cmd_data.mode = mCompile;
  83. cmd_data.output_type = otGeneral;
  84. parse_args(argc, argv, &cmd_data);
  85. rc = execute_command(&cmd_data);
  86. if (rc == 0 && cmd_data.stub_name) {
  87. fopen(cmd_data.stub_name, "w");
  88. }
  89. cleanup_tmp_dirs(&cmd_data);
  90. return rc;
  91. }
  92. void parse_args(int argc, char *argv[], cmd_data_t *cmd_data)
  93. {
  94. int a;
  95. char *arg;
  96. bool argused;
  97. for (a=1; a < argc; a++) {
  98. arg = argv[a];
  99. argused = false;
  100. if (arg[0] == '-') {
  101. if (arg[1] == '-') {
  102. argused = parse_long_opt(arg + 2, cmd_data);
  103. } else if (arg[1] == 'o' && a+1 < argc) {
  104. cmd_data->arglist[cmd_data->num_args++] = arg;
  105. arg = argv[++a];
  106. argused = parse_output_file_name(arg, cmd_data);
  107. } else {
  108. int num_used = parse_short_opt(arg + 1, cmd_data);
  109. argused = num_used > 0;
  110. if (num_used > 1) {
  111. a += num_used - 1;
  112. }
  113. }
  114. } else {
  115. argused = parse_input_file_name(arg, cmd_data);
  116. }
  117. if (!argused) {
  118. cmd_data->arglist[cmd_data->num_args++] = arg;
  119. }
  120. }
  121. post_parse_fixup(cmd_data);
  122. }
  123. bool parse_long_opt(char *arg, cmd_data_t *cmd_data)
  124. {
  125. char *equal_pos = strchr(arg, '=');
  126. char var[50];
  127. char value[500];
  128. if (equal_pos) {
  129. strncpy(var, arg, equal_pos - arg);
  130. var[equal_pos - arg] = 0;
  131. strcpy(value, equal_pos + 1);
  132. } else {
  133. strcpy(var, arg);
  134. }
  135. if (strcmp(var, "silent") == 0) {
  136. silent = true;
  137. } else if (strcmp(var, "mode") == 0) {
  138. if (strcmp(value, "compile") == 0) {
  139. cmd_data->mode = mCompile;
  140. cmd_data->output_type = otObject;
  141. }
  142. if (strcmp(value, "link") == 0) {
  143. cmd_data->mode = mLink;
  144. }
  145. if (strcmp(value, "install") == 0) {
  146. cmd_data->mode = mInstall;
  147. }
  148. } else if (strcmp(var, "shared") == 0) {
  149. shared = true;
  150. } else if (strcmp(var, "export-all") == 0) {
  151. export_all = true;
  152. } else {
  153. return false;
  154. }
  155. return true;
  156. }
  157. int parse_short_opt(char *arg, cmd_data_t *cmd_data)
  158. {
  159. if (strcmp(arg, "export-dynamic") == 0) {
  160. return 1;
  161. }
  162. if (strcmp(arg, "module") == 0) {
  163. return 1;
  164. }
  165. if (strcmp(arg, "Zexe") == 0) {
  166. return 1;
  167. }
  168. if (strcmp(arg, "avoid-version") == 0) {
  169. return 1;
  170. }
  171. if (strcmp(arg, "prefer-pic") == 0) {
  172. return 1;
  173. }
  174. if (strcmp(arg, "prefer-non-pic") == 0) {
  175. return 1;
  176. }
  177. if (strcmp(arg, "version-info") == 0 ) {
  178. return 2;
  179. }
  180. if (strcmp(arg, "no-install") == 0) {
  181. return 1;
  182. }
  183. return 0;
  184. }
  185. bool parse_input_file_name(char *arg, cmd_data_t *cmd_data)
  186. {
  187. char *ext = strrchr(arg, '.');
  188. char *name = strrchr(arg, '/');
  189. int pathlen;
  190. char *newarg;
  191. if (!ext) {
  192. return false;
  193. }
  194. ext++;
  195. if (name == NULL) {
  196. name = strrchr(arg, '\\');
  197. if (name == NULL) {
  198. name = arg;
  199. } else {
  200. name++;
  201. }
  202. } else {
  203. name++;
  204. }
  205. pathlen = name - arg;
  206. if (strcmp(ext, "lo") == 0) {
  207. newarg = (char *)malloc(strlen(arg) + 10);
  208. strcpy(newarg, arg);
  209. strcpy(newarg + (ext - arg), OBJECT_EXT);
  210. cmd_data->arglist[cmd_data->num_args++] = newarg;
  211. cmd_data->obj_files[cmd_data->num_obj_files++] = newarg;
  212. return true;
  213. }
  214. if (strcmp(ext, "la") == 0) {
  215. newarg = (char *)malloc(strlen(arg) + 10);
  216. strcpy(newarg, arg);
  217. newarg[pathlen] = 0;
  218. strcat(newarg, ".libs/");
  219. if (strncmp(name, "lib", 3) == 0) {
  220. name += 3;
  221. }
  222. strcat(newarg, name);
  223. ext = strrchr(newarg, '.') + 1;
  224. if (shared && cmd_data->mode == mInstall) {
  225. strcpy(ext, DYNAMIC_LIB_EXT);
  226. newarg = truncate_dll_name(newarg);
  227. } else {
  228. strcpy(ext, STATIC_LIB_EXT);
  229. }
  230. cmd_data->arglist[cmd_data->num_args++] = newarg;
  231. return true;
  232. }
  233. if (strcmp(ext, "c") == 0) {
  234. if (cmd_data->stub_name == NULL) {
  235. cmd_data->stub_name = (char *)malloc(strlen(arg) + 4);
  236. strcpy(cmd_data->stub_name, arg);
  237. strcpy(strrchr(cmd_data->stub_name, '.') + 1, "lo");
  238. }
  239. }
  240. if (strcmp(name, CC) == 0 || strcmp(name, CC EXE_EXT) == 0) {
  241. if (cmd_data->output_type == otGeneral) {
  242. cmd_data->output_type = otObject;
  243. }
  244. }
  245. return false;
  246. }
  247. bool parse_output_file_name(char *arg, cmd_data_t *cmd_data)
  248. {
  249. char *name = strrchr(arg, '/');
  250. char *ext = strrchr(arg, '.');
  251. char *newarg = NULL, *newext;
  252. int pathlen;
  253. if (name == NULL) {
  254. name = strrchr(arg, '\\');
  255. if (name == NULL) {
  256. name = arg;
  257. } else {
  258. name++;
  259. }
  260. } else {
  261. name++;
  262. }
  263. if (!ext) {
  264. cmd_data->stub_name = arg;
  265. cmd_data->output_type = otProgram;
  266. newarg = (char *)malloc(strlen(arg) + 5);
  267. strcpy(newarg, arg);
  268. strcat(newarg, EXE_EXT);
  269. cmd_data->arglist[cmd_data->num_args++] = newarg;
  270. cmd_data->output_name = newarg;
  271. return true;
  272. }
  273. ext++;
  274. pathlen = name - arg;
  275. if (strcmp(ext, "la") == 0) {
  276. cmd_data->stub_name = arg;
  277. cmd_data->output_type = shared ? otDynamicLibrary : otStaticLibrary;
  278. newarg = (char *)malloc(strlen(arg) + 10);
  279. mkdir(".libs", 0);
  280. strcpy(newarg, ".libs/");
  281. if (strncmp(arg, "lib", 3) == 0) {
  282. arg += 3;
  283. }
  284. strcat(newarg, arg);
  285. newext = strrchr(newarg, '.') + 1;
  286. strcpy(newext, shared ? DYNAMIC_LIB_EXT : STATIC_LIB_EXT);
  287. #ifdef TRUNCATE_DLL_NAME
  288. if (shared) {
  289. newarg = truncate_dll_name(newarg);
  290. }
  291. #endif
  292. cmd_data->arglist[cmd_data->num_args++] = newarg;
  293. cmd_data->output_name = newarg;
  294. return true;
  295. }
  296. if (strcmp(ext, "lo") == 0) {
  297. cmd_data->stub_name = arg;
  298. cmd_data->output_type = otObject;
  299. newarg = (char *)malloc(strlen(arg) + 2);
  300. strcpy(newarg, arg);
  301. ext = strrchr(newarg, '.') + 1;
  302. strcpy(ext, OBJECT_EXT);
  303. cmd_data->arglist[cmd_data->num_args++] = newarg;
  304. cmd_data->output_name = newarg;
  305. return true;
  306. }
  307. return false;
  308. }
  309. void post_parse_fixup(cmd_data_t *cmd_data)
  310. {
  311. int a;
  312. char *arg;
  313. char *ext;
  314. if (cmd_data->output_type == otStaticLibrary && cmd_data->mode == mLink) {
  315. /* We do a real hatchet job on the args when making a static library
  316. * removing all compiler switches & any other cruft that ar won't like
  317. * We also need to explode any libraries listed
  318. */
  319. for (a=0; a < cmd_data->num_args; a++) {
  320. arg = cmd_data->arglist[a];
  321. if (arg) {
  322. ext = strrchr(arg, '.');
  323. if (ext) {
  324. ext++;
  325. }
  326. if (arg[0] == '-') {
  327. cmd_data->arglist[a] = NULL;
  328. if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) {
  329. cmd_data->arglist[a+1] = NULL;
  330. }
  331. if (strcmp(arg, "-R") == 0 && a+1 < cmd_data->num_args) {
  332. cmd_data->arglist[a+1] = NULL;
  333. }
  334. if (strcmp(arg, "-version-info") == 0 && a+1 < cmd_data->num_args) {
  335. cmd_data->arglist[a+1] = NULL;
  336. }
  337. if (strcmp(arg, "-Zstack") == 0 && a+1 < cmd_data->num_args) {
  338. cmd_data->arglist[a+1] = NULL;
  339. }
  340. if (strcmp(arg, "-o") == 0) {
  341. a++;
  342. }
  343. }
  344. if (strcmp(arg, CC) == 0 || strcmp(arg, CC EXE_EXT) == 0) {
  345. cmd_data->arglist[a] = LIBRARIAN " cr";
  346. }
  347. if (ext) {
  348. if (strcmp(ext, "h") == 0 || strcmp(ext, "c") == 0) {
  349. /* ignore source files, they don't belong in a library */
  350. cmd_data->arglist[a] = NULL;
  351. }
  352. if (strcmp(ext, STATIC_LIB_EXT) == 0) {
  353. cmd_data->arglist[a] = NULL;
  354. explode_static_lib(arg, cmd_data);
  355. }
  356. }
  357. }
  358. }
  359. }
  360. if (cmd_data->output_type == otDynamicLibrary) {
  361. for (a=0; a < cmd_data->num_args; a++) {
  362. arg = cmd_data->arglist[a];
  363. if (arg) {
  364. if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) {
  365. cmd_data->arglist[a] = NULL;
  366. cmd_data->arglist[a+1] = NULL;
  367. }
  368. }
  369. }
  370. if (export_all) {
  371. generate_def_file(cmd_data);
  372. }
  373. }
  374. #if USE_OMF
  375. if (cmd_data->output_type == otObject ||
  376. cmd_data->output_type == otProgram ||
  377. cmd_data->output_type == otDynamicLibrary) {
  378. cmd_data->arglist[cmd_data->num_args++] = "-Zomf";
  379. }
  380. #endif
  381. if (shared && (cmd_data->output_type == otObject || cmd_data->output_type == otDynamicLibrary)) {
  382. cmd_data->arglist[cmd_data->num_args++] = SHARE_SW;
  383. }
  384. }
  385. int execute_command(cmd_data_t *cmd_data)
  386. {
  387. int target = 0;
  388. char *command;
  389. int a, total_len = 0;
  390. char *args[4];
  391. for (a=0; a < cmd_data->num_args; a++) {
  392. if (cmd_data->arglist[a]) {
  393. total_len += strlen(cmd_data->arglist[a]) + 1;
  394. }
  395. }
  396. command = (char *)malloc( total_len );
  397. command[0] = 0;
  398. for (a=0; a < cmd_data->num_args; a++) {
  399. if (cmd_data->arglist[a]) {
  400. strcat(command, cmd_data->arglist[a]);
  401. strcat(command, " ");
  402. }
  403. }
  404. command[strlen(command)-1] = 0;
  405. if (!silent) {
  406. puts(command);
  407. }
  408. cmd_data->num_args = target;
  409. cmd_data->arglist[cmd_data->num_args] = NULL;
  410. command = shell_esc(command);
  411. args[0] = SHELL_CMD;
  412. args[1] = "-c";
  413. args[2] = command;
  414. args[3] = NULL;
  415. return spawnvp(P_WAIT, args[0], args);
  416. }
  417. char *shell_esc(const char *str)
  418. {
  419. char *cmd;
  420. unsigned char *d;
  421. const unsigned char *s;
  422. cmd = (char *)malloc(2 * strlen(str) + 1);
  423. d = (unsigned char *)cmd;
  424. s = (const unsigned char *)str;
  425. for (; *s; ++s) {
  426. if (*s == '"' || *s == '\\') {
  427. *d++ = '\\';
  428. }
  429. *d++ = *s;
  430. }
  431. *d = '\0';
  432. return cmd;
  433. }
  434. bool explode_static_lib(char *lib, cmd_data_t *cmd_data)
  435. {
  436. char tmpdir[1024];
  437. char savewd[1024];
  438. char cmd[1024];
  439. char *name;
  440. DIR *dir;
  441. struct dirent *entry;
  442. strcpy(tmpdir, lib);
  443. strcat(tmpdir, ".exploded");
  444. mkdir(tmpdir, 0);
  445. cmd_data->tmp_dirs[cmd_data->num_tmp_dirs++] = strdup(tmpdir);
  446. getcwd(savewd, sizeof(savewd));
  447. if (chdir(tmpdir) != 0)
  448. return false;
  449. strcpy(cmd, LIBRARIAN " x ");
  450. name = strrchr(lib, '/');
  451. if (name) {
  452. name++;
  453. } else {
  454. name = lib;
  455. }
  456. strcat(cmd, "../");
  457. strcat(cmd, name);
  458. system(cmd);
  459. chdir(savewd);
  460. dir = opendir(tmpdir);
  461. while ((entry = readdir(dir)) != NULL) {
  462. if (entry->d_name[0] != '.') {
  463. strcpy(cmd, tmpdir);
  464. strcat(cmd, "/");
  465. strcat(cmd, entry->d_name);
  466. cmd_data->arglist[cmd_data->num_args++] = strdup(cmd);
  467. }
  468. }
  469. closedir(dir);
  470. return true;
  471. }
  472. void cleanup_tmp_dir(char *dirname)
  473. {
  474. DIR *dir;
  475. struct dirent *entry;
  476. char fullname[1024];
  477. dir = opendir(dirname);
  478. if (dir == NULL)
  479. return;
  480. while ((entry = readdir(dir)) != NULL) {
  481. if (entry->d_name[0] != '.') {
  482. strcpy(fullname, dirname);
  483. strcat(fullname, "/");
  484. strcat(fullname, entry->d_name);
  485. remove(fullname);
  486. }
  487. }
  488. rmdir(dirname);
  489. }
  490. void cleanup_tmp_dirs(cmd_data_t *cmd_data)
  491. {
  492. int d;
  493. for (d=0; d < cmd_data->num_tmp_dirs; d++) {
  494. cleanup_tmp_dir(cmd_data->tmp_dirs[d]);
  495. }
  496. }
  497. void generate_def_file(cmd_data_t *cmd_data)
  498. {
  499. char def_file[1024];
  500. char implib_file[1024];
  501. char *ext;
  502. FILE *hDef;
  503. char *export_args[1024];
  504. int num_export_args = 0;
  505. char *cmd;
  506. int cmd_size = 0;
  507. int a;
  508. if (cmd_data->output_name) {
  509. strcpy(def_file, cmd_data->output_name);
  510. strcat(def_file, ".def");
  511. hDef = fopen(def_file, "w");
  512. if (hDef != NULL) {
  513. fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name));
  514. fprintf(hDef, "DATA NONSHARED\n");
  515. fprintf(hDef, "EXPORTS\n");
  516. fclose(hDef);
  517. for (a=0; a < cmd_data->num_obj_files; a++) {
  518. cmd_size += strlen(cmd_data->obj_files[a]) + 1;
  519. }
  520. cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3;
  521. cmd = (char *)malloc(cmd_size);
  522. strcpy(cmd, GEN_EXPORTS);
  523. for (a=0; a < cmd_data->num_obj_files; a++) {
  524. strcat(cmd, " ");
  525. strcat(cmd, cmd_data->obj_files[a] );
  526. }
  527. strcat(cmd, ">>");
  528. strcat(cmd, def_file);
  529. puts(cmd);
  530. export_args[num_export_args++] = SHELL_CMD;
  531. export_args[num_export_args++] = "-c";
  532. export_args[num_export_args++] = cmd;
  533. export_args[num_export_args++] = NULL;
  534. spawnvp(P_WAIT, export_args[0], export_args);
  535. cmd_data->arglist[cmd_data->num_args++] = strdup(def_file);
  536. /* Now make an import library for the dll */
  537. num_export_args = 0;
  538. export_args[num_export_args++] = DEF2IMPLIB_CMD;
  539. export_args[num_export_args++] = "-o";
  540. strcpy(implib_file, ".libs/");
  541. strcat(implib_file, cmd_data->stub_name);
  542. ext = strrchr(implib_file, '.');
  543. if (ext)
  544. *ext = 0;
  545. strcat(implib_file, ".");
  546. strcat(implib_file, STATIC_LIB_EXT);
  547. export_args[num_export_args++] = implib_file;
  548. export_args[num_export_args++] = def_file;
  549. export_args[num_export_args++] = NULL;
  550. spawnvp(P_WAIT, export_args[0], export_args);
  551. }
  552. }
  553. }
  554. /* returns just a file's name without path or extension */
  555. char *nameof(char *fullpath)
  556. {
  557. char buffer[1024];
  558. char *ext;
  559. char *name = strrchr(fullpath, '/');
  560. if (name == NULL) {
  561. name = strrchr(fullpath, '\\');
  562. }
  563. if (name == NULL) {
  564. name = fullpath;
  565. } else {
  566. name++;
  567. }
  568. strcpy(buffer, name);
  569. ext = strrchr(buffer, '.');
  570. if (ext) {
  571. *ext = 0;
  572. return strdup(buffer);
  573. }
  574. return name;
  575. }
  576. char *truncate_dll_name(char *path)
  577. {
  578. /* Cut DLL name down to 8 characters after removing any mod_ prefix */
  579. char *tmppath = strdup(path);
  580. char *newname = strrchr(tmppath, '/') + 1;
  581. char *ext = strrchr(tmppath, '.');
  582. int len;
  583. if (ext == NULL)
  584. return tmppath;
  585. len = ext - newname;
  586. if (strncmp(newname, "mod_", 4) == 0) {
  587. strcpy(newname, newname + 4);
  588. len -= 4;
  589. }
  590. if (len > 8) {
  591. strcpy(newname + 8, strchr(newname, '.'));
  592. }
  593. return tmppath;
  594. }