aplibtool.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  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. char *newarg;
  190. if (!ext) {
  191. return false;
  192. }
  193. ext++;
  194. if (name == NULL) {
  195. name = strrchr(arg, '\\');
  196. if (name == NULL) {
  197. name = arg;
  198. } else {
  199. name++;
  200. }
  201. } else {
  202. name++;
  203. }
  204. if (strcmp(ext, "lo") == 0) {
  205. newarg = (char *)malloc(strlen(arg) + 10);
  206. strcpy(newarg, arg);
  207. strcpy(newarg + (ext - arg), OBJECT_EXT);
  208. cmd_data->arglist[cmd_data->num_args++] = newarg;
  209. cmd_data->obj_files[cmd_data->num_obj_files++] = newarg;
  210. return true;
  211. }
  212. if (strcmp(ext, "la") == 0) {
  213. newarg = (char *)malloc(strlen(arg) + 10);
  214. strcpy(newarg, arg);
  215. newarg[pathlen] = 0;
  216. strcat(newarg, ".libs/");
  217. if (strncmp(name, "lib", 3) == 0) {
  218. name += 3;
  219. }
  220. strcat(newarg, name);
  221. ext = strrchr(newarg, '.') + 1;
  222. if (shared && cmd_data->mode == mInstall) {
  223. strcpy(ext, DYNAMIC_LIB_EXT);
  224. newarg = truncate_dll_name(newarg);
  225. } else {
  226. strcpy(ext, STATIC_LIB_EXT);
  227. }
  228. cmd_data->arglist[cmd_data->num_args++] = newarg;
  229. return true;
  230. }
  231. if (strcmp(ext, "c") == 0) {
  232. if (cmd_data->stub_name == NULL) {
  233. cmd_data->stub_name = (char *)malloc(strlen(arg) + 4);
  234. strcpy(cmd_data->stub_name, arg);
  235. strcpy(strrchr(cmd_data->stub_name, '.') + 1, "lo");
  236. }
  237. }
  238. if (strcmp(name, CC) == 0 || strcmp(name, CC EXE_EXT) == 0) {
  239. if (cmd_data->output_type == otGeneral) {
  240. cmd_data->output_type = otObject;
  241. }
  242. }
  243. return false;
  244. }
  245. bool parse_output_file_name(char *arg, cmd_data_t *cmd_data)
  246. {
  247. char *name = strrchr(arg, '/');
  248. char *ext = strrchr(arg, '.');
  249. char *newarg = NULL, *newext;
  250. if (name == NULL) {
  251. name = strrchr(arg, '\\');
  252. if (name == NULL) {
  253. name = arg;
  254. } else {
  255. name++;
  256. }
  257. } else {
  258. name++;
  259. }
  260. if (!ext) {
  261. cmd_data->stub_name = arg;
  262. cmd_data->output_type = otProgram;
  263. newarg = (char *)malloc(strlen(arg) + 5);
  264. strcpy(newarg, arg);
  265. strcat(newarg, EXE_EXT);
  266. cmd_data->arglist[cmd_data->num_args++] = newarg;
  267. cmd_data->output_name = newarg;
  268. return true;
  269. }
  270. ext++;
  271. if (strcmp(ext, "la") == 0) {
  272. cmd_data->stub_name = arg;
  273. cmd_data->output_type = shared ? otDynamicLibrary : otStaticLibrary;
  274. newarg = (char *)malloc(strlen(arg) + 10);
  275. mkdir(".libs", 0);
  276. strcpy(newarg, ".libs/");
  277. if (strncmp(arg, "lib", 3) == 0) {
  278. arg += 3;
  279. }
  280. strcat(newarg, arg);
  281. newext = strrchr(newarg, '.') + 1;
  282. strcpy(newext, shared ? DYNAMIC_LIB_EXT : STATIC_LIB_EXT);
  283. #ifdef TRUNCATE_DLL_NAME
  284. if (shared) {
  285. newarg = truncate_dll_name(newarg);
  286. }
  287. #endif
  288. cmd_data->arglist[cmd_data->num_args++] = newarg;
  289. cmd_data->output_name = newarg;
  290. return true;
  291. }
  292. if (strcmp(ext, "lo") == 0) {
  293. cmd_data->stub_name = arg;
  294. cmd_data->output_type = otObject;
  295. newarg = (char *)malloc(strlen(arg) + 2);
  296. strcpy(newarg, arg);
  297. ext = strrchr(newarg, '.') + 1;
  298. strcpy(ext, OBJECT_EXT);
  299. cmd_data->arglist[cmd_data->num_args++] = newarg;
  300. cmd_data->output_name = newarg;
  301. return true;
  302. }
  303. return false;
  304. }
  305. void post_parse_fixup(cmd_data_t *cmd_data)
  306. {
  307. int a;
  308. char *arg;
  309. char *ext;
  310. if (cmd_data->output_type == otStaticLibrary && cmd_data->mode == mLink) {
  311. /* We do a real hatchet job on the args when making a static library
  312. * removing all compiler switches & any other cruft that ar won't like
  313. * We also need to explode any libraries listed
  314. */
  315. for (a=0; a < cmd_data->num_args; a++) {
  316. arg = cmd_data->arglist[a];
  317. if (arg) {
  318. ext = strrchr(arg, '.');
  319. if (ext) {
  320. ext++;
  321. }
  322. if (arg[0] == '-') {
  323. cmd_data->arglist[a] = NULL;
  324. if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) {
  325. cmd_data->arglist[a+1] = NULL;
  326. }
  327. if (strcmp(arg, "-R") == 0 && a+1 < cmd_data->num_args) {
  328. cmd_data->arglist[a+1] = NULL;
  329. }
  330. if (strcmp(arg, "-version-info") == 0 && a+1 < cmd_data->num_args) {
  331. cmd_data->arglist[a+1] = NULL;
  332. }
  333. if (strcmp(arg, "-Zstack") == 0 && a+1 < cmd_data->num_args) {
  334. cmd_data->arglist[a+1] = NULL;
  335. }
  336. if (strcmp(arg, "-o") == 0) {
  337. a++;
  338. }
  339. }
  340. if (strcmp(arg, CC) == 0 || strcmp(arg, CC EXE_EXT) == 0) {
  341. cmd_data->arglist[a] = LIBRARIAN " cr";
  342. }
  343. if (ext) {
  344. if (strcmp(ext, "h") == 0 || strcmp(ext, "c") == 0) {
  345. /* ignore source files, they don't belong in a library */
  346. cmd_data->arglist[a] = NULL;
  347. }
  348. if (strcmp(ext, STATIC_LIB_EXT) == 0) {
  349. cmd_data->arglist[a] = NULL;
  350. explode_static_lib(arg, cmd_data);
  351. }
  352. }
  353. }
  354. }
  355. }
  356. if (cmd_data->output_type == otDynamicLibrary) {
  357. for (a=0; a < cmd_data->num_args; a++) {
  358. arg = cmd_data->arglist[a];
  359. if (arg) {
  360. if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) {
  361. cmd_data->arglist[a] = NULL;
  362. cmd_data->arglist[a+1] = NULL;
  363. }
  364. }
  365. }
  366. if (export_all) {
  367. generate_def_file(cmd_data);
  368. }
  369. }
  370. #if USE_OMF
  371. if (cmd_data->output_type == otObject ||
  372. cmd_data->output_type == otProgram ||
  373. cmd_data->output_type == otDynamicLibrary) {
  374. cmd_data->arglist[cmd_data->num_args++] = "-Zomf";
  375. }
  376. #endif
  377. if (shared && (cmd_data->output_type == otObject || cmd_data->output_type == otDynamicLibrary)) {
  378. cmd_data->arglist[cmd_data->num_args++] = SHARE_SW;
  379. }
  380. }
  381. int execute_command(cmd_data_t *cmd_data)
  382. {
  383. int target = 0;
  384. char *command;
  385. int a, total_len = 0;
  386. char *args[4];
  387. for (a=0; a < cmd_data->num_args; a++) {
  388. if (cmd_data->arglist[a]) {
  389. total_len += strlen(cmd_data->arglist[a]) + 1;
  390. }
  391. }
  392. command = (char *)malloc( total_len );
  393. command[0] = 0;
  394. for (a=0; a < cmd_data->num_args; a++) {
  395. if (cmd_data->arglist[a]) {
  396. strcat(command, cmd_data->arglist[a]);
  397. strcat(command, " ");
  398. }
  399. }
  400. command[strlen(command)-1] = 0;
  401. if (!silent) {
  402. puts(command);
  403. }
  404. cmd_data->num_args = target;
  405. cmd_data->arglist[cmd_data->num_args] = NULL;
  406. command = shell_esc(command);
  407. args[0] = SHELL_CMD;
  408. args[1] = "-c";
  409. args[2] = command;
  410. args[3] = NULL;
  411. return spawnvp(P_WAIT, args[0], args);
  412. }
  413. char *shell_esc(const char *str)
  414. {
  415. char *cmd;
  416. unsigned char *d;
  417. const unsigned char *s;
  418. cmd = (char *)malloc(2 * strlen(str) + 1);
  419. d = (unsigned char *)cmd;
  420. s = (const unsigned char *)str;
  421. for (; *s; ++s) {
  422. if (*s == '"' || *s == '\\') {
  423. *d++ = '\\';
  424. }
  425. *d++ = *s;
  426. }
  427. *d = '\0';
  428. return cmd;
  429. }
  430. bool explode_static_lib(char *lib, cmd_data_t *cmd_data)
  431. {
  432. char tmpdir[1024];
  433. char savewd[1024];
  434. char cmd[1024];
  435. char *name;
  436. DIR *dir;
  437. struct dirent *entry;
  438. strcpy(tmpdir, lib);
  439. strcat(tmpdir, ".exploded");
  440. mkdir(tmpdir, 0);
  441. cmd_data->tmp_dirs[cmd_data->num_tmp_dirs++] = strdup(tmpdir);
  442. getcwd(savewd, sizeof(savewd));
  443. if (chdir(tmpdir) != 0)
  444. return false;
  445. strcpy(cmd, LIBRARIAN " x ");
  446. name = strrchr(lib, '/');
  447. if (name) {
  448. name++;
  449. } else {
  450. name = lib;
  451. }
  452. strcat(cmd, "../");
  453. strcat(cmd, name);
  454. system(cmd);
  455. chdir(savewd);
  456. dir = opendir(tmpdir);
  457. while ((entry = readdir(dir)) != NULL) {
  458. if (entry->d_name[0] != '.') {
  459. strcpy(cmd, tmpdir);
  460. strcat(cmd, "/");
  461. strcat(cmd, entry->d_name);
  462. cmd_data->arglist[cmd_data->num_args++] = strdup(cmd);
  463. }
  464. }
  465. closedir(dir);
  466. return true;
  467. }
  468. void cleanup_tmp_dir(char *dirname)
  469. {
  470. DIR *dir;
  471. struct dirent *entry;
  472. char fullname[1024];
  473. dir = opendir(dirname);
  474. if (dir == NULL)
  475. return;
  476. while ((entry = readdir(dir)) != NULL) {
  477. if (entry->d_name[0] != '.') {
  478. strcpy(fullname, dirname);
  479. strcat(fullname, "/");
  480. strcat(fullname, entry->d_name);
  481. remove(fullname);
  482. }
  483. }
  484. rmdir(dirname);
  485. }
  486. void cleanup_tmp_dirs(cmd_data_t *cmd_data)
  487. {
  488. int d;
  489. for (d=0; d < cmd_data->num_tmp_dirs; d++) {
  490. cleanup_tmp_dir(cmd_data->tmp_dirs[d]);
  491. }
  492. }
  493. void generate_def_file(cmd_data_t *cmd_data)
  494. {
  495. char def_file[1024];
  496. char implib_file[1024];
  497. char *ext;
  498. FILE *hDef;
  499. char *export_args[1024];
  500. int num_export_args = 0;
  501. char *cmd;
  502. int cmd_size = 0;
  503. int a;
  504. if (cmd_data->output_name) {
  505. strcpy(def_file, cmd_data->output_name);
  506. strcat(def_file, ".def");
  507. hDef = fopen(def_file, "w");
  508. if (hDef != NULL) {
  509. fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name));
  510. fprintf(hDef, "DATA NONSHARED\n");
  511. fprintf(hDef, "EXPORTS\n");
  512. fclose(hDef);
  513. for (a=0; a < cmd_data->num_obj_files; a++) {
  514. cmd_size += strlen(cmd_data->obj_files[a]) + 1;
  515. }
  516. cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3;
  517. cmd = (char *)malloc(cmd_size);
  518. strcpy(cmd, GEN_EXPORTS);
  519. for (a=0; a < cmd_data->num_obj_files; a++) {
  520. strcat(cmd, " ");
  521. strcat(cmd, cmd_data->obj_files[a] );
  522. }
  523. strcat(cmd, ">>");
  524. strcat(cmd, def_file);
  525. puts(cmd);
  526. export_args[num_export_args++] = SHELL_CMD;
  527. export_args[num_export_args++] = "-c";
  528. export_args[num_export_args++] = cmd;
  529. export_args[num_export_args++] = NULL;
  530. spawnvp(P_WAIT, export_args[0], export_args);
  531. cmd_data->arglist[cmd_data->num_args++] = strdup(def_file);
  532. /* Now make an import library for the dll */
  533. num_export_args = 0;
  534. export_args[num_export_args++] = DEF2IMPLIB_CMD;
  535. export_args[num_export_args++] = "-o";
  536. strcpy(implib_file, ".libs/");
  537. strcat(implib_file, cmd_data->stub_name);
  538. ext = strrchr(implib_file, '.');
  539. if (ext)
  540. *ext = 0;
  541. strcat(implib_file, ".");
  542. strcat(implib_file, STATIC_LIB_EXT);
  543. export_args[num_export_args++] = implib_file;
  544. export_args[num_export_args++] = def_file;
  545. export_args[num_export_args++] = NULL;
  546. spawnvp(P_WAIT, export_args[0], export_args);
  547. }
  548. }
  549. }
  550. /* returns just a file's name without path or extension */
  551. char *nameof(char *fullpath)
  552. {
  553. char buffer[1024];
  554. char *ext;
  555. char *name = strrchr(fullpath, '/');
  556. if (name == NULL) {
  557. name = strrchr(fullpath, '\\');
  558. }
  559. if (name == NULL) {
  560. name = fullpath;
  561. } else {
  562. name++;
  563. }
  564. strcpy(buffer, name);
  565. ext = strrchr(buffer, '.');
  566. if (ext) {
  567. *ext = 0;
  568. return strdup(buffer);
  569. }
  570. return name;
  571. }
  572. char *truncate_dll_name(char *path)
  573. {
  574. /* Cut DLL name down to 8 characters after removing any mod_ prefix */
  575. char *tmppath = strdup(path);
  576. char *newname = strrchr(tmppath, '/') + 1;
  577. char *ext = strrchr(tmppath, '.');
  578. int len;
  579. if (ext == NULL)
  580. return tmppath;
  581. len = ext - newname;
  582. if (strncmp(newname, "mod_", 4) == 0) {
  583. strcpy(newname, newname + 4);
  584. len -= 4;
  585. }
  586. if (len > 8) {
  587. strcpy(newname + 8, strchr(newname, '.'));
  588. }
  589. return tmppath;
  590. }