]> git.saurik.com Git - apple/icu.git/blob - icuSources/tools/pkgdata/pkgdata.cpp
ICU-461.13.tar.gz
[apple/icu.git] / icuSources / tools / pkgdata / pkgdata.cpp
1 /******************************************************************************
2 * Copyright (C) 2000-2011, International Business Machines
3 * Corporation and others. All Rights Reserved.
4 *******************************************************************************
5 * file name: pkgdata.c
6 * encoding: ANSI X3.4 (1968)
7 * tab size: 8 (not used)
8 * indentation:4
9 *
10 * created on: 2000may15
11 * created by: Steven \u24C7 Loomis
12 *
13 * This program packages the ICU data into different forms
14 * (DLL, common data, etc.)
15 */
16
17 /*
18 * We define _XOPEN_SOURCE so that we can get popen and pclose.
19 */
20 #if !defined(_XOPEN_SOURCE)
21 #if __STDC_VERSION__ >= 199901L
22 /* It is invalid to compile an XPG3, XPG4, XPG4v2 or XPG5 application using c99 on Solaris */
23 #define _XOPEN_SOURCE 600
24 #else
25 #define _XOPEN_SOURCE 4
26 #endif
27 #endif
28
29
30 #include "unicode/utypes.h"
31
32 #if U_HAVE_POPEN
33 #if defined(U_CYGWIN) && defined(__STRICT_ANSI__)
34 /* popen/pclose aren't defined in strict ANSI on Cygwin */
35 #undef __STRICT_ANSI__
36 #endif
37 #endif
38
39 #include "unicode/putil.h"
40 #include "cmemory.h"
41 #include "cstring.h"
42 #include "filestrm.h"
43 #include "toolutil.h"
44 #include "unicode/uclean.h"
45 #include "unewdata.h"
46 #include "uoptions.h"
47 #include "putilimp.h"
48 #include "package.h"
49 #include "pkg_icu.h"
50 #include "pkg_genc.h"
51 #include "pkg_gencmn.h"
52 #include "flagparser.h"
53 #include "filetools.h"
54
55
56 #if U_HAVE_POPEN
57 # include <unistd.h>
58 #endif
59 #include <stdio.h>
60 #include <stdlib.h>
61
62 U_CDECL_BEGIN
63 #include "pkgtypes.h"
64 U_CDECL_END
65
66 #ifdef U_WINDOWS
67 #ifdef __GNUC__
68 #define WINDOWS_WITH_GNUC
69 #else
70 #define WINDOWS_WITH_MSVC
71 #endif
72 #endif
73 #if !defined(WINDOWS_WITH_MSVC) && !defined(U_LINUX)
74 #define BUILD_DATA_WITHOUT_ASSEMBLY
75 #endif
76 #if defined(WINDOWS_WITH_MSVC) || defined(U_LINUX)
77 #define CAN_WRITE_OBJ_CODE
78 #endif
79 #if defined(U_CYGWIN) || defined(CYGWINMSVC)
80 #define USING_CYGWIN
81 #endif
82
83 /*
84 * When building the data library without assembly,
85 * some platforms use a single c code file for all of
86 * the data to generate the final data library. This can
87 * increase the performance of the pkdata tool.
88 */
89 #if defined(OS400)
90 #define USE_SINGLE_CCODE_FILE
91 #endif
92
93 /* Need to fix the file seperator character when using MinGW. */
94 #if defined(WINDOWS_WITH_GNUC) || defined(USING_CYGWIN)
95 #define PKGDATA_FILE_SEP_STRING "/"
96 #else
97 #define PKGDATA_FILE_SEP_STRING U_FILE_SEP_STRING
98 #endif
99
100 #define LARGE_BUFFER_MAX_SIZE 2048
101 #define SMALL_BUFFER_MAX_SIZE 512
102 #define BUFFER_PADDING_SIZE 20
103
104 static void loadLists(UPKGOptions *o, UErrorCode *status);
105
106 static int32_t pkg_executeOptions(UPKGOptions *o);
107
108 #ifdef WINDOWS_WITH_MSVC
109 static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o);
110 #endif
111 static int32_t pkg_createSymLinks(const char *targetDir, UBool specialHandling=FALSE);
112 static int32_t pkg_installLibrary(const char *installDir, const char *dir);
113 static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName);
114 static int32_t pkg_installCommonMode(const char *installDir, const char *fileName);
115
116 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
117 static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode);
118 #endif
119
120 static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath);
121 static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command = NULL);
122 static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt);
123 static void createFileNames(UPKGOptions *o, const char mode, const char *version_major, const char *version, const char *libName, const UBool reverseExt);
124 static int32_t initializePkgDataFlags(UPKGOptions *o);
125
126 static int32_t pkg_getOptionsFromICUConfig(UBool verbose, UOption *option);
127 static int runCommand(const char* command, UBool specialHandling=FALSE);
128
129 enum {
130 NAME,
131 BLDOPT,
132 MODE,
133 HELP,
134 HELP_QUESTION_MARK,
135 VERBOSE,
136 COPYRIGHT,
137 COMMENT,
138 DESTDIR,
139 REBUILD,
140 TEMPDIR,
141 INSTALL,
142 SOURCEDIR,
143 ENTRYPOINT,
144 REVISION,
145 FORCE_PREFIX,
146 LIBNAME,
147 QUIET
148 };
149
150 /* This sets the modes that are available */
151 static struct {
152 const char *name, *alt_name;
153 const char *desc;
154 } modes[] = {
155 { "files", 0, "Uses raw data files (no effect). Installation copies all files to the target location." },
156 #ifdef U_WINDOWS
157 { "dll", "library", "Generates one common data file and one shared library, <package>.dll"},
158 { "common", "archive", "Generates just the common file, <package>.dat"},
159 { "static", "static", "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
160 #else
161 #ifdef UDATA_SO_SUFFIX
162 { "dll", "library", "Generates one shared library, <package>" UDATA_SO_SUFFIX },
163 #endif
164 { "common", "archive", "Generates one common data file, <package>.dat" },
165 { "static", "static", "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
166 #endif
167 };
168
169 static UOption options[]={
170 /*00*/ UOPTION_DEF( "name", 'p', UOPT_REQUIRES_ARG),
171 /*01*/ UOPTION_DEF( "bldopt", 'O', UOPT_REQUIRES_ARG), /* on Win32 it is release or debug */
172 /*02*/ UOPTION_DEF( "mode", 'm', UOPT_REQUIRES_ARG),
173 /*03*/ UOPTION_HELP_H, /* -h */
174 /*04*/ UOPTION_HELP_QUESTION_MARK, /* -? */
175 /*05*/ UOPTION_VERBOSE, /* -v */
176 /*06*/ UOPTION_COPYRIGHT, /* -c */
177 /*07*/ UOPTION_DEF( "comment", 'C', UOPT_REQUIRES_ARG),
178 /*08*/ UOPTION_DESTDIR, /* -d */
179 /*11*/ UOPTION_DEF( "rebuild", 'F', UOPT_NO_ARG),
180 /*12*/ UOPTION_DEF( "tempdir", 'T', UOPT_REQUIRES_ARG),
181 /*13*/ UOPTION_DEF( "install", 'I', UOPT_REQUIRES_ARG),
182 /*14*/ UOPTION_SOURCEDIR ,
183 /*15*/ UOPTION_DEF( "entrypoint", 'e', UOPT_REQUIRES_ARG),
184 /*16*/ UOPTION_DEF( "revision", 'r', UOPT_REQUIRES_ARG),
185 /*17*/ UOPTION_DEF( "force-prefix", 'f', UOPT_NO_ARG),
186 /*18*/ UOPTION_DEF( "libname", 'L', UOPT_REQUIRES_ARG),
187 /*19*/ UOPTION_DEF( "quiet", 'q', UOPT_NO_ARG)
188 };
189
190 enum {
191 GENCCODE_ASSEMBLY_TYPE,
192 SO_EXT,
193 SOBJ_EXT,
194 A_EXT,
195 LIBPREFIX,
196 LIB_EXT_ORDER,
197 COMPILER,
198 LIBFLAGS,
199 GENLIB,
200 LDICUDTFLAGS,
201 LD_SONAME,
202 RPATH_FLAGS,
203 BIR_FLAGS,
204 AR,
205 ARFLAGS,
206 RANLIB,
207 INSTALL_CMD,
208 PKGDATA_FLAGS_SIZE
209 };
210 static char **pkgDataFlags = NULL;
211
212 enum {
213 LIB_FILE,
214 LIB_FILE_VERSION_MAJOR,
215 LIB_FILE_VERSION,
216 LIB_FILE_VERSION_TMP,
217 #ifdef U_CYGWIN
218 LIB_FILE_CYGWIN,
219 LIB_FILE_CYGWIN_VERSION,
220 #endif
221 LIB_FILENAMES_SIZE
222 };
223 static char libFileNames[LIB_FILENAMES_SIZE][256];
224
225 static UPKGOptions *pkg_checkFlag(UPKGOptions *o);
226
227 const char options_help[][320]={
228 "Set the data name",
229 #ifdef U_MAKE_IS_NMAKE
230 "The directory where the ICU is located (e.g. <ICUROOT> which contains the bin directory)",
231 #else
232 "Specify options for the builder.",
233 #endif
234 "Specify the mode of building (see below; default: common)",
235 "This usage text",
236 "This usage text",
237 "Make the output verbose",
238 "Use the standard ICU copyright",
239 "Use a custom comment (instead of the copyright)",
240 "Specify the destination directory for files",
241 "Force rebuilding of all data",
242 "Specify temporary dir (default: output dir)",
243 "Install the data (specify target)",
244 "Specify a custom source directory",
245 "Specify a custom entrypoint name (default: short name)",
246 "Specify a version when packaging in dll or static mode",
247 "Add package to all file names if not present",
248 "Library name to build (if different than package name)",
249 "Quite mode. (e.g. Do not output a readme file for static libraries)"
250 };
251
252 const char *progname = "PKGDATA";
253
254 int
255 main(int argc, char* argv[]) {
256 int result = 0;
257 /* FileStream *out; */
258 UPKGOptions o;
259 CharList *tail;
260 UBool needsHelp = FALSE;
261 UErrorCode status = U_ZERO_ERROR;
262 /* char tmp[1024]; */
263 uint32_t i;
264 int32_t n;
265
266 U_MAIN_INIT_ARGS(argc, argv);
267
268 progname = argv[0];
269
270 options[MODE].value = "common";
271
272 /* read command line options */
273 argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
274
275 /* error handling, printing usage message */
276 /* I've decided to simply print an error and quit. This tool has too
277 many options to just display them all of the time. */
278
279 if(options[HELP].doesOccur || options[HELP_QUESTION_MARK].doesOccur) {
280 needsHelp = TRUE;
281 }
282 else {
283 if(!needsHelp && argc<0) {
284 fprintf(stderr,
285 "%s: error in command line argument \"%s\"\n",
286 progname,
287 argv[-argc]);
288 fprintf(stderr, "Run '%s --help' for help.\n", progname);
289 return 1;
290 }
291
292
293 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
294 if(!options[BLDOPT].doesOccur && uprv_strcmp(options[MODE].value, "common") != 0) {
295 if (pkg_getOptionsFromICUConfig(options[VERBOSE].doesOccur, &options[BLDOPT]) != 0) {
296 fprintf(stderr, " required parameter is missing: -O is required for static and shared builds.\n");
297 fprintf(stderr, "Run '%s --help' for help.\n", progname);
298 return 1;
299 }
300 }
301 #else
302 if(options[BLDOPT].doesOccur) {
303 fprintf(stdout, "Warning: You are using the -O option which is not needed for MSVC build on Windows.\n");
304 }
305 #endif
306
307 if(!options[NAME].doesOccur) /* -O we already have - don't report it. */
308 {
309 fprintf(stderr, " required parameter -p is missing \n");
310 fprintf(stderr, "Run '%s --help' for help.\n", progname);
311 return 1;
312 }
313
314 if(argc == 1) {
315 fprintf(stderr,
316 "No input files specified.\n"
317 "Run '%s --help' for help.\n", progname);
318 return 1;
319 }
320 } /* end !needsHelp */
321
322 if(argc<0 || needsHelp ) {
323 fprintf(stderr,
324 "usage: %s [-options] [-] [packageFile] \n"
325 "\tProduce packaged ICU data from the given list(s) of files.\n"
326 "\t'-' by itself means to read from stdin.\n"
327 "\tpackageFile is a text file containing the list of files to package.\n",
328 progname);
329
330 fprintf(stderr, "\n options:\n");
331 for(i=0;i<(sizeof(options)/sizeof(options[0]));i++) {
332 fprintf(stderr, "%-5s -%c %s%-10s %s\n",
333 (i<1?"[REQ]":""),
334 options[i].shortName,
335 options[i].longName ? "or --" : " ",
336 options[i].longName ? options[i].longName : "",
337 options_help[i]);
338 }
339
340 fprintf(stderr, "modes: (-m option)\n");
341 for(i=0;i<(sizeof(modes)/sizeof(modes[0]));i++) {
342 fprintf(stderr, " %-9s ", modes[i].name);
343 if (modes[i].alt_name) {
344 fprintf(stderr, "/ %-9s", modes[i].alt_name);
345 } else {
346 fprintf(stderr, " ");
347 }
348 fprintf(stderr, " %s\n", modes[i].desc);
349 }
350 return 1;
351 }
352
353 /* OK, fill in the options struct */
354 uprv_memset(&o, 0, sizeof(o));
355
356 o.mode = options[MODE].value;
357 o.version = options[REVISION].doesOccur ? options[REVISION].value : 0;
358
359 o.shortName = options[NAME].value;
360 {
361 int32_t len = (int32_t)uprv_strlen(o.shortName);
362 char *csname, *cp;
363 const char *sp;
364
365 cp = csname = (char *) uprv_malloc((len + 1 + 1) * sizeof(*o.cShortName));
366 if (*(sp = o.shortName)) {
367 *cp++ = isalpha(*sp) ? * sp : '_';
368 for (++sp; *sp; ++sp) {
369 *cp++ = isalnum(*sp) ? *sp : '_';
370 }
371 }
372 *cp = 0;
373
374 o.cShortName = csname;
375 }
376
377 if(options[LIBNAME].doesOccur) { /* get libname from shortname, or explicit -L parameter */
378 o.libName = options[LIBNAME].value;
379 } else {
380 o.libName = o.shortName;
381 }
382
383 if(options[QUIET].doesOccur) {
384 o.quiet = TRUE;
385 } else {
386 o.quiet = FALSE;
387 }
388
389 o.verbose = options[VERBOSE].doesOccur;
390
391
392 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) /* on UNIX, we'll just include the file... */
393 if (options[BLDOPT].doesOccur) {
394 o.options = options[BLDOPT].value;
395 } else {
396 o.options = NULL;
397 }
398 #endif
399 if(options[COPYRIGHT].doesOccur) {
400 o.comment = U_COPYRIGHT_STRING;
401 } else if (options[COMMENT].doesOccur) {
402 o.comment = options[COMMENT].value;
403 }
404
405 if( options[DESTDIR].doesOccur ) {
406 o.targetDir = options[DESTDIR].value;
407 } else {
408 o.targetDir = "."; /* cwd */
409 }
410
411 o.rebuild = options[REBUILD].doesOccur;
412
413 if( options[TEMPDIR].doesOccur ) {
414 o.tmpDir = options[TEMPDIR].value;
415 } else {
416 o.tmpDir = o.targetDir;
417 }
418
419 if( options[INSTALL].doesOccur ) {
420 o.install = options[INSTALL].value;
421 } else {
422 o.install = NULL;
423 }
424
425 if( options[SOURCEDIR].doesOccur ) {
426 o.srcDir = options[SOURCEDIR].value;
427 } else {
428 o.srcDir = ".";
429 }
430
431 if( options[ENTRYPOINT].doesOccur ) {
432 o.entryName = options[ENTRYPOINT].value;
433 } else {
434 o.entryName = o.cShortName;
435 }
436
437 /* OK options are set up. Now the file lists. */
438 tail = NULL;
439 for( n=1; n<argc; n++) {
440 o.fileListFiles = pkg_appendToList(o.fileListFiles, &tail, uprv_strdup(argv[n]));
441 }
442
443 /* load the files */
444 loadLists(&o, &status);
445 if( U_FAILURE(status) ) {
446 fprintf(stderr, "error loading input file lists: %s\n", u_errorName(status));
447 return 2;
448 }
449
450 result = pkg_executeOptions(&o);
451
452 if (pkgDataFlags != NULL) {
453 for (n = 0; n < PKGDATA_FLAGS_SIZE; n++) {
454 if (pkgDataFlags[n] != NULL) {
455 uprv_free(pkgDataFlags[n]);
456 }
457 }
458 uprv_free(pkgDataFlags);
459 }
460
461 if (o.cShortName != NULL) {
462 uprv_free((char *)o.cShortName);
463 }
464 if (o.fileListFiles != NULL) {
465 pkg_deleteList(o.fileListFiles);
466 }
467 if (o.filePaths != NULL) {
468 pkg_deleteList(o.filePaths);
469 }
470 if (o.files != NULL) {
471 pkg_deleteList(o.files);
472 }
473
474 return result;
475 }
476
477 static int runCommand(const char* command, UBool specialHandling) {
478 char *cmd = NULL;
479 char cmdBuffer[SMALL_BUFFER_MAX_SIZE];
480 int32_t len = strlen(command);
481
482 if (len == 0) {
483 return 0;
484 }
485
486 if (!specialHandling) {
487 #if defined(USING_CYGWIN) || defined(OS400)
488 if ((len + BUFFER_PADDING_SIZE) >= SMALL_BUFFER_MAX_SIZE) {
489 cmd = (char *)uprv_malloc(len + BUFFER_PADDING_SIZE);
490 } else {
491 cmd = cmdBuffer;
492 }
493 #ifdef USING_CYGWIN
494 sprintf(cmd, "bash -c \"%s\"", command);
495
496 #elif defined(OS400)
497 sprintf(cmd, "QSH CMD('%s')", command);
498 #endif
499 #else
500 goto normal_command_mode;
501 #endif
502 } else {
503 normal_command_mode:
504 cmd = (char *)command;
505 }
506
507 printf("pkgdata: %s\n", cmd);
508 int result = system(cmd);
509 if (result != 0) {
510 printf("-- return status = %d\n", result);
511 }
512
513 if (cmd != cmdBuffer && cmd != command) {
514 uprv_free(cmd);
515 }
516
517 return result;
518 }
519
520 #define LN_CMD "ln -s"
521 #define RM_CMD "rm -f"
522
523 #define MODE_COMMON 'c'
524 #define MODE_STATIC 's'
525 #define MODE_DLL 'd'
526 #define MODE_FILES 'f'
527
528 static int32_t pkg_executeOptions(UPKGOptions *o) {
529 int32_t result = 0;
530
531 const char mode = o->mode[0];
532 char targetDir[SMALL_BUFFER_MAX_SIZE] = "";
533 char tmpDir[SMALL_BUFFER_MAX_SIZE] = "";
534 char datFileName[SMALL_BUFFER_MAX_SIZE] = "";
535 char datFileNamePath[LARGE_BUFFER_MAX_SIZE] = "";
536 char checkLibFile[LARGE_BUFFER_MAX_SIZE] = "";
537
538 initializePkgDataFlags(o);
539
540 if (mode == MODE_FILES) {
541 /* Copy the raw data to the installation directory. */
542 if (o->install != NULL) {
543 uprv_strcpy(targetDir, o->install);
544 if (o->shortName != NULL) {
545 uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING);
546 uprv_strcat(targetDir, o->shortName);
547 }
548
549 if(o->verbose) {
550 fprintf(stdout, "# Install: Files mode, copying files to %s..\n", targetDir);
551 }
552 result = pkg_installFileMode(targetDir, o->srcDir, o->fileListFiles->str);
553 }
554 return result;
555 } else /* if (mode == MODE_COMMON || mode == MODE_STATIC || mode == MODE_DLL) */ {
556 uprv_strcpy(targetDir, o->targetDir);
557 uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING);
558
559 uprv_strcpy(tmpDir, o->tmpDir);
560 uprv_strcat(tmpDir, PKGDATA_FILE_SEP_STRING);
561
562 uprv_strcpy(datFileNamePath, tmpDir);
563
564 uprv_strcpy(datFileName, o->shortName);
565 uprv_strcat(datFileName, UDATA_CMN_SUFFIX);
566
567 uprv_strcat(datFileNamePath, datFileName);
568
569 if(o->verbose) {
570 fprintf(stdout, "# Writing package file %s ..\n", datFileNamePath);
571 }
572 result = writePackageDatFile(datFileNamePath, o->comment, o->srcDir, o->fileListFiles->str, NULL, U_CHARSET_FAMILY ? 'e' : U_IS_BIG_ENDIAN ? 'b' : 'l');
573 if (result != 0) {
574 fprintf(stderr,"Error writing package dat file.\n");
575 return result;
576 }
577
578 if (mode == MODE_COMMON) {
579 char targetFileNamePath[LARGE_BUFFER_MAX_SIZE] = "";
580
581 uprv_strcpy(targetFileNamePath, targetDir);
582 uprv_strcat(targetFileNamePath, datFileName);
583
584 if (T_FileStream_file_exists(targetFileNamePath)) {
585 if ((result = remove(targetFileNamePath)) != 0) {
586 fprintf(stderr, "Unable to remove old dat file: %s\n", targetFileNamePath);
587 return result;
588 }
589 }
590
591 /* Move the dat file created to the target directory. */
592 result = rename(datFileNamePath, targetFileNamePath);
593
594 if(o->verbose) {
595 fprintf(stdout, "# Moving package file to %s ..\n", targetFileNamePath);
596 }
597 if (result != 0) {
598 fprintf(stderr, "Unable to move dat file (%s) to target location (%s).\n", datFileNamePath, targetFileNamePath);
599 }
600
601 if (o->install != NULL) {
602 result = pkg_installCommonMode(o->install, targetFileNamePath);
603 }
604
605 return result;
606 } else /* if (mode[0] == MODE_STATIC || mode[0] == MODE_DLL) */ {
607 char gencFilePath[SMALL_BUFFER_MAX_SIZE] = "";
608 char version_major[10] = "";
609 UBool reverseExt = FALSE;
610
611 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
612 /* Get the version major number. */
613 if (o->version != NULL) {
614 for (uint32_t i = 0;i < sizeof(version_major);i++) {
615 if (o->version[i] == '.') {
616 version_major[i] = 0;
617 break;
618 }
619 version_major[i] = o->version[i];
620 }
621 }
622
623 #ifndef OS400
624 /* Certain platforms have different library extension ordering. (e.g. libicudata.##.so vs libicudata.so.##)
625 * reverseExt is FALSE if the suffix should be the version number.
626 */
627 if (pkgDataFlags[LIB_EXT_ORDER][uprv_strlen(pkgDataFlags[LIB_EXT_ORDER])-1] == pkgDataFlags[SO_EXT][uprv_strlen(pkgDataFlags[SO_EXT])-1]) {
628 reverseExt = TRUE;
629 }
630 #endif
631 /* Using the base libName and version number, generate the library file names. */
632 createFileNames(o, mode, version_major, o->version, o->libName, reverseExt);
633
634 if ((o->version!=NULL || (mode==MODE_STATIC)) && o->rebuild == FALSE) {
635 /* Check to see if a previous built data library file exists and check if it is the latest. */
636 sprintf(checkLibFile, "%s%s", targetDir, libFileNames[LIB_FILE_VERSION]);
637 if (T_FileStream_file_exists(checkLibFile)) {
638 if (isFileModTimeLater(checkLibFile, o->srcDir, TRUE) && isFileModTimeLater(checkLibFile, o->options)) {
639 if (o->install != NULL) {
640 if(o->verbose) {
641 fprintf(stdout, "# Installing already-built library into %s\n", o->install);
642 }
643 result = pkg_installLibrary(o->install, targetDir);
644 } else {
645 if(o->verbose) {
646 printf("# Not rebuilding %s - up to date.\n", checkLibFile);
647 }
648 }
649 return result;
650 } else if (o->verbose && (o->install!=NULL)) {
651 fprintf(stdout, "# Not installing up-to-date library %s into %s\n", checkLibFile, o->install);
652 }
653 } else if(o->verbose && (o->install!=NULL)) {
654 fprintf(stdout, "# Not installing missing %s into %s\n", checkLibFile, o->install);
655 }
656 }
657
658 pkg_checkFlag(o);
659 #endif
660
661 if (pkgDataFlags[GENCCODE_ASSEMBLY_TYPE][0] != 0) {
662 const char* genccodeAssembly = pkgDataFlags[GENCCODE_ASSEMBLY_TYPE];
663
664 if(o->verbose) {
665 fprintf(stdout, "# Generating assembly code %s of type %s ..\n", gencFilePath, genccodeAssembly);
666 }
667
668 /* Offset genccodeAssembly by 3 because "-a " */
669 if (genccodeAssembly &&
670 (uprv_strlen(genccodeAssembly)>3) &&
671 checkAssemblyHeaderName(genccodeAssembly+3)) {
672 writeAssemblyCode(datFileNamePath, o->tmpDir, o->entryName, NULL, gencFilePath);
673
674 result = pkg_createWithAssemblyCode(targetDir, mode, gencFilePath);
675 if (result != 0) {
676 fprintf(stderr, "Error generating assembly code for data.\n");
677 return result;
678 } else if (mode == MODE_STATIC) {
679 if(o->install != NULL) {
680 if(o->verbose) {
681 fprintf(stdout, "# Installing static library into %s\n", o->install);
682 }
683 result = pkg_installLibrary(o->install, targetDir);
684 }
685 return result;
686 }
687 } else {
688 fprintf(stderr,"Assembly type \"%s\" is unknown.\n", genccodeAssembly);
689 return -1;
690 }
691 } else {
692 if(o->verbose) {
693 fprintf(stdout, "# Writing object code to %s ..\n", gencFilePath);
694 }
695 #ifdef CAN_WRITE_OBJ_CODE
696 writeObjectCode(datFileNamePath, o->tmpDir, o->entryName, NULL, NULL, gencFilePath);
697 #ifdef U_LINUX
698 result = pkg_generateLibraryFile(targetDir, mode, gencFilePath);
699 #elif defined(WINDOWS_WITH_MSVC)
700 result = pkg_createWindowsDLL(mode, gencFilePath, o);
701 #endif
702 #elif defined(BUILD_DATA_WITHOUT_ASSEMBLY)
703 result = pkg_createWithoutAssemblyCode(o, targetDir, mode);
704 #endif
705 if (result != 0) {
706 fprintf(stderr, "Error generating package data.\n");
707 return result;
708 }
709 }
710 #ifndef U_WINDOWS
711 if(mode != MODE_STATIC) {
712 /* Certain platforms uses archive library. (e.g. AIX) */
713 if(o->verbose) {
714 fprintf(stdout, "# Creating data archive library file ..\n");
715 }
716 result = pkg_archiveLibrary(targetDir, o->version, reverseExt);
717 if (result != 0) {
718 fprintf(stderr, "Error creating data archive library file.\n");
719 return result;
720 }
721 #ifndef OS400
722 /* Create symbolic links for the final library file. */
723 result = pkg_createSymLinks(targetDir);
724 if (result != 0) {
725 fprintf(stderr, "Error creating symbolic links of the data library file.\n");
726 return result;
727 }
728 #endif
729 } /* !MODE_STATIC */
730 #endif
731
732 #if !defined(U_WINDOWS) || defined(USING_CYGWIN)
733 /* Install the libraries if option was set. */
734 if (o->install != NULL) {
735 if(o->verbose) {
736 fprintf(stdout, "# Installing library file to %s ..\n", o->install);
737 }
738 result = pkg_installLibrary(o->install, targetDir);
739 if (result != 0) {
740 fprintf(stderr, "Error installing the data library.\n");
741 return result;
742 }
743 }
744 #endif
745 }
746 }
747 return result;
748 }
749
750 /* Initialize the pkgDataFlags with the option file given. */
751 static int32_t initializePkgDataFlags(UPKGOptions *o) {
752 UErrorCode status = U_ZERO_ERROR;
753 int32_t result = 0;
754 int32_t currentBufferSize = SMALL_BUFFER_MAX_SIZE;
755 int32_t tmpResult = 0;
756
757 /* Initialize pkgdataFlags */
758 pkgDataFlags = (char**)uprv_malloc(sizeof(char*) * PKGDATA_FLAGS_SIZE);
759
760 /* If we run out of space, allocate more */
761 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
762 do {
763 #endif
764 if (pkgDataFlags != NULL) {
765 for (int32_t i = 0; i < PKGDATA_FLAGS_SIZE; i++) {
766 pkgDataFlags[i] = (char*)uprv_malloc(sizeof(char) * currentBufferSize);
767 if (pkgDataFlags[i] != NULL) {
768 pkgDataFlags[i][0] = 0;
769 } else {
770 fprintf(stderr,"Error allocating memory for pkgDataFlags.\n");
771 return -1;
772 }
773 }
774 } else {
775 fprintf(stderr,"Error allocating memory for pkgDataFlags.\n");
776 return -1;
777 }
778
779 if (o->options == NULL) {
780 return result;
781 }
782
783 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
784 /* Read in options file. */
785 if(o->verbose) {
786 fprintf(stdout, "# Reading options file %s\n", o->options);
787 }
788 status = U_ZERO_ERROR;
789 tmpResult = parseFlagsFile(o->options, pkgDataFlags, currentBufferSize, (int32_t)PKGDATA_FLAGS_SIZE, &status);
790 if (status == U_BUFFER_OVERFLOW_ERROR) {
791 for (int32_t i = 0; i < PKGDATA_FLAGS_SIZE; i++) {
792 uprv_free(pkgDataFlags[i]);
793 }
794 currentBufferSize = tmpResult;
795 } else if (U_FAILURE(status)) {
796 fprintf(stderr,"Unable to open or read \"%s\" option file. status = %s\n", o->options, u_errorName(status));
797 return -1;
798 }
799 #endif
800 if(o->verbose) {
801 fprintf(stdout, "# pkgDataFlags=");
802 for(int32_t i=0;i<PKGDATA_FLAGS_SIZE && pkgDataFlags[i][0];i++) {
803 fprintf(stdout, "%c \"%s\"", (i>0)?',':' ',pkgDataFlags[i]);
804 }
805 fprintf(stdout, "\n");
806 }
807 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
808 } while (status == U_BUFFER_OVERFLOW_ERROR);
809 #endif
810
811 return result;
812 }
813
814
815 /*
816 * Given the base libName and version numbers, generate the libary file names and store it in libFileNames.
817 * Depending on the configuration, the library name may either end with version number or shared object suffix.
818 */
819 static void createFileNames(UPKGOptions *o, const char mode, const char *version_major, const char *version, const char *libName, UBool reverseExt) {
820 sprintf(libFileNames[LIB_FILE], "%s%s",
821 pkgDataFlags[LIBPREFIX],
822 libName);
823
824 if(o->verbose) {
825 fprintf(stdout, "# libFileName[LIB_FILE] = %s\n", libFileNames[LIB_FILE]);
826 }
827
828 if (version != NULL) {
829 #ifdef U_CYGWIN
830 sprintf(libFileNames[LIB_FILE_CYGWIN], "cyg%s.%s",
831 libName,
832 pkgDataFlags[SO_EXT]);
833 sprintf(libFileNames[LIB_FILE_CYGWIN_VERSION], "cyg%s%s.%s",
834 libName,
835 version_major,
836 pkgDataFlags[SO_EXT]);
837
838 uprv_strcat(pkgDataFlags[SO_EXT], ".");
839 uprv_strcat(pkgDataFlags[SO_EXT], pkgDataFlags[A_EXT]);
840
841 #elif defined(OS400) || defined(_AIX)
842 sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s.%s",
843 libFileNames[LIB_FILE],
844 pkgDataFlags[SOBJ_EXT]);
845 #else
846 sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s.%s",
847 libFileNames[LIB_FILE],
848 pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
849 reverseExt ? version : pkgDataFlags[SOBJ_EXT],
850 reverseExt ? pkgDataFlags[SOBJ_EXT] : version);
851 #endif
852 sprintf(libFileNames[LIB_FILE_VERSION_MAJOR], "%s%s%s.%s",
853 libFileNames[LIB_FILE],
854 pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
855 reverseExt ? version_major : pkgDataFlags[SO_EXT],
856 reverseExt ? pkgDataFlags[SO_EXT] : version_major);
857
858 sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s.%s",
859 libFileNames[LIB_FILE],
860 pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
861 reverseExt ? version : pkgDataFlags[SO_EXT],
862 reverseExt ? pkgDataFlags[SO_EXT] : version);
863
864 if(o->verbose) {
865 fprintf(stdout, "# libFileName[LIB_FILE_VERSION] = %s\n", libFileNames[LIB_FILE_VERSION]);
866 }
867
868 #ifdef U_CYGWIN
869 /* Cygwin only deals with the version major number. */
870 uprv_strcpy(libFileNames[LIB_FILE_VERSION_TMP], libFileNames[LIB_FILE_VERSION_MAJOR]);
871 #endif
872 }
873 if(mode == MODE_STATIC) {
874 sprintf(libFileNames[LIB_FILE_VERSION], "%s.%s", libFileNames[LIB_FILE], pkgDataFlags[A_EXT]);
875 libFileNames[LIB_FILE_VERSION_MAJOR][0]=0;
876 if(o->verbose) {
877 fprintf(stdout, "# libFileName[LIB_FILE_VERSION] = %s (static)\n", libFileNames[LIB_FILE_VERSION]);
878 }
879 }
880 }
881
882 /* Create the symbolic links for the final library file. */
883 static int32_t pkg_createSymLinks(const char *targetDir, UBool specialHandling) {
884 int32_t result = 0;
885 char cmd[LARGE_BUFFER_MAX_SIZE];
886 char name1[SMALL_BUFFER_MAX_SIZE]; /* symlink file name */
887 char name2[SMALL_BUFFER_MAX_SIZE]; /* file name to symlink */
888
889 #ifndef USING_CYGWIN
890 /* No symbolic link to make. */
891 if (uprv_strlen(libFileNames[LIB_FILE_VERSION]) == 0 || uprv_strlen(libFileNames[LIB_FILE_VERSION_MAJOR]) == 0 ||
892 uprv_strcmp(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_MAJOR]) == 0) {
893 return result;
894 }
895
896 sprintf(cmd, "cd %s && %s %s && %s %s %s",
897 targetDir,
898 RM_CMD,
899 libFileNames[LIB_FILE_VERSION_MAJOR],
900 LN_CMD,
901 libFileNames[LIB_FILE_VERSION],
902 libFileNames[LIB_FILE_VERSION_MAJOR]);
903 result = runCommand(cmd);
904 if (result != 0) {
905 return result;
906 }
907 #endif
908
909 if (specialHandling) {
910 #ifdef U_CYGWIN
911 sprintf(name1, "%s", libFileNames[LIB_FILE_CYGWIN]);
912 sprintf(name2, "%s", libFileNames[LIB_FILE_CYGWIN_VERSION]);
913 #else
914 goto normal_symlink_mode;
915 #endif
916 } else {
917 normal_symlink_mode:
918 sprintf(name1, "%s.%s", libFileNames[LIB_FILE], pkgDataFlags[SO_EXT]);
919 sprintf(name2, "%s", libFileNames[LIB_FILE_VERSION]);
920 }
921
922 sprintf(cmd, "cd %s && %s %s && %s %s %s",
923 targetDir,
924 RM_CMD,
925 name1,
926 LN_CMD,
927 name2,
928 name1);
929
930 result = runCommand(cmd);
931
932 return result;
933 }
934
935 static int32_t pkg_installLibrary(const char *installDir, const char *targetDir) {
936 int32_t result = 0;
937 char cmd[SMALL_BUFFER_MAX_SIZE];
938
939 sprintf(cmd, "cd %s && %s %s %s%s%s",
940 targetDir,
941 pkgDataFlags[INSTALL_CMD],
942 libFileNames[LIB_FILE_VERSION],
943 installDir, PKGDATA_FILE_SEP_STRING, libFileNames[LIB_FILE_VERSION]
944 );
945
946 result = runCommand(cmd);
947
948 if (result != 0) {
949 return result;
950 }
951
952 #ifdef CYGWINMSVC
953 sprintf(cmd, "cd %s && %s %s.lib %s",
954 targetDir,
955 pkgDataFlags[INSTALL_CMD],
956 libFileNames[LIB_FILE],
957 installDir
958 );
959 result = runCommand(cmd);
960
961 if (result != 0) {
962 return result;
963 }
964 #elif defined (U_CYGWIN)
965 sprintf(cmd, "cd %s && %s %s %s",
966 targetDir,
967 pkgDataFlags[INSTALL_CMD],
968 libFileNames[LIB_FILE_CYGWIN_VERSION],
969 installDir
970 );
971 result = runCommand(cmd);
972
973 if (result != 0) {
974 return result;
975 }
976 #endif
977
978 return pkg_createSymLinks(installDir, TRUE);
979 }
980
981 static int32_t pkg_installCommonMode(const char *installDir, const char *fileName) {
982 int32_t result = 0;
983 char cmd[SMALL_BUFFER_MAX_SIZE] = "";
984
985 if (!T_FileStream_file_exists(installDir)) {
986 UErrorCode status = U_ZERO_ERROR;
987
988 uprv_mkdir(installDir, &status);
989 if (U_FAILURE(status)) {
990 fprintf(stderr, "Error creating installation directory: %s\n", installDir);
991 return -1;
992 }
993 }
994 #ifndef U_WINDOWS_WITH_MSVC
995 sprintf(cmd, "%s %s %s", pkgDataFlags[INSTALL_CMD], fileName, installDir);
996 #else
997 sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, fileName, installDir, WIN_INSTALL_CMD_FLAGS);
998 #endif
999
1000 result = runCommand(cmd);
1001 if (result != 0) {
1002 fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
1003 }
1004
1005 return result;
1006 }
1007
1008 #ifdef U_WINDOWS_MSVC
1009 /* Copy commands for installing the raw data files on Windows. */
1010 #define WIN_INSTALL_CMD "xcopy"
1011 #define WIN_INSTALL_CMD_FLAGS "/E /Y /K"
1012 #endif
1013 static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName) {
1014 int32_t result = 0;
1015 char cmd[SMALL_BUFFER_MAX_SIZE] = "";
1016
1017 if (!T_FileStream_file_exists(installDir)) {
1018 UErrorCode status = U_ZERO_ERROR;
1019
1020 uprv_mkdir(installDir, &status);
1021 if (U_FAILURE(status)) {
1022 fprintf(stderr, "Error creating installation directory: %s\n", installDir);
1023 return -1;
1024 }
1025 }
1026 #ifndef U_WINDOWS_WITH_MSVC
1027 char buffer[SMALL_BUFFER_MAX_SIZE] = "";
1028
1029 FileStream *f = T_FileStream_open(fileListName, "r");
1030 if (f != NULL) {
1031 for(;;) {
1032 if (T_FileStream_readLine(f, buffer, SMALL_BUFFER_MAX_SIZE) != NULL) {
1033 /* Remove new line character. */
1034 buffer[uprv_strlen(buffer)-1] = 0;
1035
1036 sprintf(cmd, "%s %s%s%s %s%s%s",
1037 pkgDataFlags[INSTALL_CMD],
1038 srcDir, PKGDATA_FILE_SEP_STRING, buffer,
1039 installDir, PKGDATA_FILE_SEP_STRING, buffer);
1040
1041 result = runCommand(cmd);
1042 if (result != 0) {
1043 fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
1044 break;
1045 }
1046 } else {
1047 if (!T_FileStream_eof(f)) {
1048 fprintf(stderr, "Failed to read line from file: %s\n", fileListName);
1049 result = -1;
1050 }
1051 break;
1052 }
1053 }
1054 T_FileStream_close(f);
1055 } else {
1056 result = -1;
1057 fprintf(stderr, "Unable to open list file: %s\n", fileListName);
1058 }
1059 #else
1060 sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, srcDir, installDir, WIN_INSTALL_CMD_FLAGS);
1061 result = runCommand(cmd);
1062 if (result != 0) {
1063 fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
1064 }
1065 #endif
1066
1067 return result;
1068 }
1069
1070 /* Archiving of the library file may be needed depending on the platform and options given.
1071 * If archiving is not needed, copy over the library file name.
1072 */
1073 static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt) {
1074 int32_t result = 0;
1075 char cmd[LARGE_BUFFER_MAX_SIZE];
1076
1077 /* If the shared object suffix and the final object suffix is different and the final object suffix and the
1078 * archive file suffix is the same, then the final library needs to be archived.
1079 */
1080 if (uprv_strcmp(pkgDataFlags[SOBJ_EXT], pkgDataFlags[SO_EXT]) != 0 && uprv_strcmp(pkgDataFlags[A_EXT], pkgDataFlags[SO_EXT]) == 0) {
1081 sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s.%s",
1082 libFileNames[LIB_FILE],
1083 pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
1084 reverseExt ? version : pkgDataFlags[SO_EXT],
1085 reverseExt ? pkgDataFlags[SO_EXT] : version);
1086
1087 sprintf(cmd, "%s %s %s%s %s%s",
1088 pkgDataFlags[AR],
1089 pkgDataFlags[ARFLAGS],
1090 targetDir,
1091 libFileNames[LIB_FILE_VERSION],
1092 targetDir,
1093 libFileNames[LIB_FILE_VERSION_TMP]);
1094
1095 result = runCommand(cmd);
1096 if (result != 0) {
1097 return result;
1098 }
1099
1100 sprintf(cmd, "%s %s%s",
1101 pkgDataFlags[RANLIB],
1102 targetDir,
1103 libFileNames[LIB_FILE_VERSION]);
1104
1105 result = runCommand(cmd);
1106 if (result != 0) {
1107 return result;
1108 }
1109
1110 /* Remove unneeded library file. */
1111 sprintf(cmd, "%s %s%s",
1112 RM_CMD,
1113 targetDir,
1114 libFileNames[LIB_FILE_VERSION_TMP]);
1115
1116 result = runCommand(cmd);
1117 if (result != 0) {
1118 return result;
1119 }
1120
1121 } else {
1122 uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]);
1123 }
1124
1125 return result;
1126 }
1127
1128 /*
1129 * Using the compiler information from the configuration file set by -O option, generate the library file.
1130 * command may be given to allow for a larger buffer for cmd.
1131 */
1132 static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command) {
1133 int32_t result = 0;
1134 char *cmd = NULL;
1135 UBool freeCmd = FALSE;
1136 int32_t length = 0;
1137
1138 /* This is necessary because if packaging is done without assembly code, objectFile might be extremely large
1139 * containing many object files and so the calling function should supply a command buffer that is large
1140 * enough to handle this. Otherwise, use the default size.
1141 */
1142 if (command != NULL) {
1143 cmd = command;
1144 }
1145
1146 if (mode == MODE_STATIC) {
1147 if (cmd == NULL) {
1148 length = uprv_strlen(pkgDataFlags[AR]) + uprv_strlen(pkgDataFlags[ARFLAGS]) + uprv_strlen(targetDir) +
1149 uprv_strlen(libFileNames[LIB_FILE_VERSION]) + uprv_strlen(objectFile) + uprv_strlen(pkgDataFlags[RANLIB]) + BUFFER_PADDING_SIZE;
1150 if ((cmd = (char *)uprv_malloc(sizeof(char) * length)) == NULL) {
1151 fprintf(stderr, "Unable to allocate memory for command.\n");
1152 return -1;
1153 }
1154 freeCmd = TRUE;
1155 }
1156 sprintf(cmd, "%s %s %s%s %s",
1157 pkgDataFlags[AR],
1158 pkgDataFlags[ARFLAGS],
1159 targetDir,
1160 libFileNames[LIB_FILE_VERSION],
1161 objectFile);
1162
1163 result = runCommand(cmd);
1164 if (result == 0) {
1165 sprintf(cmd, "%s %s%s",
1166 pkgDataFlags[RANLIB],
1167 targetDir,
1168 libFileNames[LIB_FILE_VERSION]);
1169
1170 result = runCommand(cmd);
1171 }
1172 } else /* if (mode == MODE_DLL) */ {
1173 if (cmd == NULL) {
1174 length = uprv_strlen(pkgDataFlags[GENLIB]) + uprv_strlen(pkgDataFlags[LDICUDTFLAGS]) +
1175 uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_VERSION_TMP]) +
1176 uprv_strlen(objectFile) + uprv_strlen(pkgDataFlags[LD_SONAME]) +
1177 uprv_strlen(pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR]) +
1178 uprv_strlen(pkgDataFlags[RPATH_FLAGS]) + uprv_strlen(pkgDataFlags[BIR_FLAGS]) + BUFFER_PADDING_SIZE;
1179 #ifdef U_CYGWIN
1180 length += uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_CYGWIN_VERSION]);
1181 #endif
1182 if ((cmd = (char *)uprv_malloc(sizeof(char) * length)) == NULL) {
1183 fprintf(stderr, "Unable to allocate memory for command.\n");
1184 return -1;
1185 }
1186 freeCmd = TRUE;
1187 }
1188 #ifdef U_CYGWIN
1189 sprintf(cmd, "%s%s%s %s -o %s%s %s %s%s %s %s",
1190 pkgDataFlags[GENLIB],
1191 targetDir,
1192 libFileNames[LIB_FILE_VERSION_TMP],
1193 pkgDataFlags[LDICUDTFLAGS],
1194 targetDir, libFileNames[LIB_FILE_CYGWIN_VERSION],
1195 #else
1196 sprintf(cmd, "%s %s -o %s%s %s %s%s %s %s",
1197 pkgDataFlags[GENLIB],
1198 pkgDataFlags[LDICUDTFLAGS],
1199 targetDir,
1200 libFileNames[LIB_FILE_VERSION_TMP],
1201 #endif
1202 objectFile,
1203 pkgDataFlags[LD_SONAME],
1204 pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR],
1205 pkgDataFlags[RPATH_FLAGS],
1206 pkgDataFlags[BIR_FLAGS]);
1207
1208 /* Generate the library file. */
1209 result = runCommand(cmd);
1210 }
1211
1212 if (freeCmd) {
1213 uprv_free(cmd);
1214 }
1215
1216 return result;
1217 }
1218
1219 static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath) {
1220 char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
1221 char *cmd;
1222 int32_t result = 0;
1223
1224 int32_t length = 0;
1225
1226 /* Remove the ending .s and replace it with .o for the new object file. */
1227 uprv_strcpy(tempObjectFile, gencFilePath);
1228 tempObjectFile[uprv_strlen(tempObjectFile)-1] = 'o';
1229
1230 length = uprv_strlen(pkgDataFlags[COMPILER]) + uprv_strlen(pkgDataFlags[LIBFLAGS])
1231 + uprv_strlen(tempObjectFile) + uprv_strlen(gencFilePath) + BUFFER_PADDING_SIZE;
1232
1233 cmd = (char *)uprv_malloc(sizeof(char) * length);
1234 if (cmd == NULL) {
1235 return -1;
1236 }
1237
1238 /* Generate the object file. */
1239 sprintf(cmd, "%s %s -o %s %s",
1240 pkgDataFlags[COMPILER],
1241 pkgDataFlags[LIBFLAGS],
1242 tempObjectFile,
1243 gencFilePath);
1244
1245 result = runCommand(cmd);
1246 uprv_free(cmd);
1247 if (result != 0) {
1248 return result;
1249 }
1250
1251 return pkg_generateLibraryFile(targetDir, mode, tempObjectFile);
1252 }
1253
1254 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
1255 /*
1256 * Generation of the data library without assembly code needs to compile each data file
1257 * individually and then link it all together.
1258 * Note: Any update to the directory structure of the data needs to be reflected here.
1259 */
1260 enum {
1261 DATA_PREFIX_BRKITR,
1262 DATA_PREFIX_COLL,
1263 DATA_PREFIX_CURR,
1264 DATA_PREFIX_LANG,
1265 DATA_PREFIX_RBNF,
1266 DATA_PREFIX_REGION,
1267 DATA_PREFIX_TRANSLIT,
1268 DATA_PREFIX_ZONE,
1269 DATA_PREFIX_LENGTH
1270 };
1271
1272 const static char DATA_PREFIX[DATA_PREFIX_LENGTH][10] = {
1273 "brkitr",
1274 "coll",
1275 "curr",
1276 "lang",
1277 "rbnf",
1278 "region",
1279 "translit",
1280 "zone"
1281 };
1282
1283 static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode) {
1284 int32_t result = 0;
1285 CharList *list = o->filePaths;
1286 CharList *listNames = o->files;
1287 int32_t listSize = pkg_countCharList(list);
1288 char *buffer;
1289 char *cmd;
1290 char gencmnFile[SMALL_BUFFER_MAX_SIZE] = "";
1291 char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
1292 #ifdef USE_SINGLE_CCODE_FILE
1293 char icudtAll[SMALL_BUFFER_MAX_SIZE] = "";
1294
1295 sprintf(icudtAll, "%s%s%sall.c",
1296 o->tmpDir,
1297 PKGDATA_FILE_SEP_STRING,
1298 libFileNames[LIB_FILE]);
1299 /* Remove previous icudtall.c file. */
1300 if (T_FileStream_file_exists(icudtAll) && (result = remove(icudtAll)) != 0) {
1301 fprintf(stderr, "Unable to remove old icudtall file: %s\n", icudtAll);
1302 return result;
1303 }
1304 #endif
1305
1306 if (list == NULL || listNames == NULL) {
1307 /* list and listNames should never be NULL since we are looping through the CharList with
1308 * the given size.
1309 */
1310 return -1;
1311 }
1312
1313 if ((cmd = (char *)uprv_malloc((listSize + 2) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
1314 fprintf(stderr, "Unable to allocate memory for cmd.\n");
1315 return -1;
1316 } else if ((buffer = (char *)uprv_malloc((listSize + 1) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
1317 fprintf(stderr, "Unable to allocate memory for buffer.\n");
1318 uprv_free(cmd);
1319 return -1;
1320 }
1321
1322 for (int32_t i = 0; i < (listSize + 1); i++) {
1323 const char *file ;
1324 const char *name;
1325
1326 if (i == 0) {
1327 /* The first iteration calls the gencmn function and initailizes the buffer. */
1328 createCommonDataFile(o->tmpDir, o->shortName, o->entryName, NULL, o->srcDir, o->comment, o->fileListFiles->str, 0, TRUE, o->verbose, gencmnFile);
1329 buffer[0] = 0;
1330 #ifdef USE_SINGLE_CCODE_FILE
1331 uprv_strcpy(tempObjectFile, gencmnFile);
1332 tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
1333
1334 sprintf(cmd, "%s %s -o %s %s"
1335 pkgDataFlags[COMPILER],
1336 pkgDataFlags[LIBFLAGS],
1337 tempObjectFile,
1338 gencmnFile);
1339
1340 result = runCommand(cmd);
1341 if (result != 0) {
1342 break;
1343 }
1344
1345 sprintf(buffer, "%s",tempObjectFile);
1346 #endif
1347 } else {
1348 char newName[SMALL_BUFFER_MAX_SIZE];
1349 char dataName[SMALL_BUFFER_MAX_SIZE];
1350 char dataDirName[SMALL_BUFFER_MAX_SIZE];
1351 const char *pSubstring;
1352 file = list->str;
1353 name = listNames->str;
1354
1355 newName[0] = dataName[0] = 0;
1356 for (int32_t n = 0; n < DATA_PREFIX_LENGTH; n++) {
1357 dataDirName[0] = 0;
1358 sprintf(dataDirName, "%s%s", DATA_PREFIX[n], PKGDATA_FILE_SEP_STRING);
1359 /* If the name contains a prefix (indicating directory), alter the new name accordingly. */
1360 pSubstring = uprv_strstr(name, dataDirName);
1361 if (pSubstring != NULL) {
1362 char newNameTmp[SMALL_BUFFER_MAX_SIZE] = "";
1363 const char *p = name + uprv_strlen(dataDirName);
1364 for (int32_t i = 0;;i++) {
1365 if (p[i] == '.') {
1366 newNameTmp[i] = '_';
1367 continue;
1368 }
1369 newNameTmp[i] = p[i];
1370 if (p[i] == 0) {
1371 break;
1372 }
1373 }
1374 sprintf(newName, "%s_%s",
1375 DATA_PREFIX[n],
1376 newNameTmp);
1377 sprintf(dataName, "%s_%s",
1378 o->shortName,
1379 DATA_PREFIX[n]);
1380 }
1381 if (newName[0] != 0) {
1382 break;
1383 }
1384 }
1385
1386 writeCCode(file, o->tmpDir, dataName[0] != 0 ? dataName : o->shortName, newName[0] != 0 ? newName : NULL, gencmnFile);
1387 #ifdef USE_SINGLE_CCODE_FILE
1388 sprintf(cmd, "cat %s >> %s", gencmnFile, icudtAll);
1389
1390 result = runCommand(cmd);
1391 if (result != 0) {
1392 break;
1393 } else {
1394 /* Remove the c code file after concatenating it to icudtall.c file. */
1395 if ((result = remove(gencmnFile)) != 0) {
1396 fprintf(stderr, "Unable to remove c code file: %s\n", gencmnFile);
1397 return result;
1398 }
1399 }
1400 #endif
1401 }
1402
1403 #ifndef USE_SINGLE_CCODE_FILE
1404 uprv_strcpy(tempObjectFile, gencmnFile);
1405 tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
1406
1407 sprintf(cmd, "%s %s -o %s %s",
1408 pkgDataFlags[COMPILER],
1409 pkgDataFlags[LIBFLAGS],
1410 tempObjectFile,
1411 gencmnFile);
1412 result = runCommand(cmd);
1413 if (result != 0) {
1414 break;
1415 }
1416
1417 uprv_strcat(buffer, " ");
1418 uprv_strcat(buffer, tempObjectFile);
1419
1420 #endif
1421
1422 if (i > 0) {
1423 list = list->next;
1424 listNames = listNames->next;
1425 }
1426 }
1427
1428 #ifdef USE_SINGLE_CCODE_FILE
1429 uprv_strcpy(tempObjectFile, icudtAll);
1430 tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
1431
1432 sprintf(cmd, "%s %s -o %s %s",
1433 pkgDataFlags[COMPILER],
1434 pkgDataFlags[LIBFLAGS],
1435 tempObjectFile,
1436 icudtAll);
1437
1438 result = runCommand(cmd);
1439 if (result == 0) {
1440 uprv_strcat(buffer, " ");
1441 uprv_strcat(buffer, tempObjectFile);
1442 }
1443 #endif
1444
1445 if (result == 0) {
1446 /* Generate the library file. */
1447 result = pkg_generateLibraryFile(targetDir, mode, buffer, cmd);
1448 }
1449
1450 uprv_free(buffer);
1451 uprv_free(cmd);
1452
1453 return result;
1454 }
1455 #endif
1456
1457 #ifdef WINDOWS_WITH_MSVC
1458 #define LINK_CMD "link.exe /nologo /release /out:"
1459 #define LINK_FLAGS "/DLL /NOENTRY /MANIFEST:NO /base:0x4ad00000 /implib:"
1460 #define LIB_CMD "LIB.exe /nologo /out:"
1461 #define LIB_FILE "icudt.lib"
1462 #define LIB_EXT UDATA_LIB_SUFFIX
1463 #define DLL_EXT UDATA_SO_SUFFIX
1464
1465 static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o) {
1466 char cmd[LARGE_BUFFER_MAX_SIZE];
1467 if (mode == MODE_STATIC) {
1468 char staticLibFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1469
1470 uprv_strcpy(staticLibFilePath, o->tmpDir);
1471 uprv_strcat(staticLibFilePath, PKGDATA_FILE_SEP_STRING);
1472
1473 uprv_strcat(staticLibFilePath, o->entryName);
1474 uprv_strcat(staticLibFilePath, LIB_EXT);
1475
1476 sprintf(cmd, "%s\"%s\" \"%s\"",
1477 LIB_CMD,
1478 staticLibFilePath,
1479 gencFilePath);
1480 } else if (mode == MODE_DLL) {
1481 char dllFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1482 char libFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1483 char resFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1484 char tmpResFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1485
1486 #ifdef CYGWINMSVC
1487 uprv_strcpy(dllFilePath, o->targetDir);
1488 #else
1489 uprv_strcpy(dllFilePath, o->srcDir);
1490 #endif
1491 uprv_strcat(dllFilePath, PKGDATA_FILE_SEP_STRING);
1492 uprv_strcpy(libFilePath, dllFilePath);
1493
1494 #ifdef CYGWINMSVC
1495 uprv_strcat(libFilePath, o->libName);
1496 uprv_strcat(libFilePath, ".lib");
1497
1498 uprv_strcat(dllFilePath, o->libName);
1499 uprv_strcat(dllFilePath, o->version);
1500 #else
1501 if (strstr(o->libName, "icudt")) {
1502 uprv_strcat(libFilePath, LIB_FILE);
1503 } else {
1504 uprv_strcat(libFilePath, o->libName);
1505 uprv_strcat(libFilePath, ".lib");
1506 }
1507 uprv_strcat(dllFilePath, o->entryName);
1508 #endif
1509 uprv_strcat(dllFilePath, DLL_EXT);
1510
1511 uprv_strcpy(tmpResFilePath, o->tmpDir);
1512 uprv_strcat(tmpResFilePath, PKGDATA_FILE_SEP_STRING);
1513 uprv_strcat(tmpResFilePath, ICUDATA_RES_FILE);
1514
1515 if (T_FileStream_file_exists(tmpResFilePath)) {
1516 sprintf(resFilePath, "\"%s\"", tmpResFilePath);
1517 }
1518
1519 /* Check if dll file and lib file exists and that it is not newer than genc file. */
1520 if (!o->rebuild && (T_FileStream_file_exists(dllFilePath) && isFileModTimeLater(dllFilePath, gencFilePath)) &&
1521 (T_FileStream_file_exists(libFilePath) && isFileModTimeLater(libFilePath, gencFilePath))) {
1522 if(o->verbose) {
1523 printf("# Not rebuilding %s - up to date.\n", gencFilePath);
1524 }
1525 return 0;
1526 }
1527
1528 sprintf(cmd, "%s\"%s\" %s\"%s\" \"%s\" %s",
1529 LINK_CMD,
1530 dllFilePath,
1531 LINK_FLAGS,
1532 libFilePath,
1533 gencFilePath,
1534 resFilePath
1535 );
1536 }
1537
1538 return runCommand(cmd, TRUE);
1539 }
1540 #endif
1541
1542 static UPKGOptions *pkg_checkFlag(UPKGOptions *o) {
1543 #ifdef U_AIX
1544 /* AIX needs a map file. */
1545 char *flag = NULL;
1546 int32_t length = 0;
1547 char tmpbuffer[SMALL_BUFFER_MAX_SIZE];
1548 const char MAP_FILE_EXT[] = ".map";
1549 FileStream *f = NULL;
1550 char mapFile[SMALL_BUFFER_MAX_SIZE] = "";
1551 int32_t start = -1;
1552 int32_t count = 0;
1553
1554 flag = pkgDataFlags[BIR_FLAGS];
1555 length = uprv_strlen(pkgDataFlags[BIR_FLAGS]);
1556
1557 for (int32_t i = 0; i < length; i++) {
1558 if (flag[i] == MAP_FILE_EXT[count]) {
1559 if (count == 0) {
1560 start = i;
1561 }
1562 count++;
1563 } else {
1564 count = 0;
1565 }
1566
1567 if (count == uprv_strlen(MAP_FILE_EXT)) {
1568 break;
1569 }
1570 }
1571
1572 if (start >= 0) {
1573 int32_t index = 0;
1574 for (int32_t i = 0;;i++) {
1575 if (i == start) {
1576 for (int32_t n = 0;;n++) {
1577 if (o->shortName[n] == 0) {
1578 break;
1579 }
1580 tmpbuffer[index++] = o->shortName[n];
1581 }
1582 }
1583
1584 tmpbuffer[index++] = flag[i];
1585
1586 if (flag[i] == 0) {
1587 break;
1588 }
1589 }
1590
1591 uprv_memset(flag, 0, length);
1592 uprv_strcpy(flag, tmpbuffer);
1593
1594 uprv_strcpy(mapFile, o->shortName);
1595 uprv_strcat(mapFile, MAP_FILE_EXT);
1596
1597 f = T_FileStream_open(mapFile, "w");
1598 if (f == NULL) {
1599 fprintf(stderr,"Unable to create map file: %s.\n", mapFile);
1600 } else {
1601 sprintf(tmpbuffer, "%s%s ", o->entryName, UDATA_CMN_INTERMEDIATE_SUFFIX);
1602
1603 T_FileStream_writeLine(f, tmpbuffer);
1604
1605 T_FileStream_close(f);
1606 }
1607 }
1608 #elif defined(U_CYGWIN)
1609 /* Cygwin needs to change flag options. */
1610 char *flag = NULL;
1611 int32_t length = 0;
1612
1613 flag = pkgDataFlags[GENLIB];
1614 length = uprv_strlen(pkgDataFlags[GENLIB]);
1615
1616 int32_t position = length - 1;
1617
1618 for(;position >= 0;position--) {
1619 if (flag[position] == '=') {
1620 position++;
1621 break;
1622 }
1623 }
1624
1625 uprv_memset(flag + position, 0, length - position);
1626 #elif defined(OS400)
1627 /* OS400 needs to fix the ld options (swap single quote with double quote) */
1628 char *flag = NULL;
1629 int32_t length = 0;
1630
1631 flag = pkgDataFlags[GENLIB];
1632 length = uprv_strlen(pkgDataFlags[GENLIB]);
1633
1634 int32_t position = length - 1;
1635
1636 for(int32_t i = 0; i < length; i++) {
1637 if (flag[i] == '\'') {
1638 flag[i] = '\"';
1639 }
1640 }
1641 #endif
1642 // Don't really need a return value, just need to stop compiler warnings about
1643 // the unused parameter 'o' on platforms where it is not otherwise used.
1644 return o;
1645 }
1646
1647 static void loadLists(UPKGOptions *o, UErrorCode *status)
1648 {
1649 CharList *l, *tail = NULL, *tail2 = NULL;
1650 FileStream *in;
1651 char line[16384];
1652 char *linePtr, *lineNext;
1653 const uint32_t lineMax = 16300;
1654 char tmp[1024];
1655 char *s;
1656 int32_t ln=0; /* line number */
1657
1658 for(l = o->fileListFiles; l; l = l->next) {
1659 if(o->verbose) {
1660 fprintf(stdout, "# pkgdata: Reading %s..\n", l->str);
1661 }
1662 /* TODO: stdin */
1663 in = T_FileStream_open(l->str, "r"); /* open files list */
1664
1665 if(!in) {
1666 fprintf(stderr, "Error opening <%s>.\n", l->str);
1667 *status = U_FILE_ACCESS_ERROR;
1668 return;
1669 }
1670
1671 while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) { /* for each line */
1672 ln++;
1673 if(uprv_strlen(line)>lineMax) {
1674 fprintf(stderr, "%s:%d - line too long (over %d chars)\n", l->str, (int)ln, (int)lineMax);
1675 exit(1);
1676 }
1677 /* remove spaces at the beginning */
1678 linePtr = line;
1679 while(isspace(*linePtr)) {
1680 linePtr++;
1681 }
1682 s=linePtr;
1683 /* remove trailing newline characters */
1684 while(*s!=0) {
1685 if(*s=='\r' || *s=='\n') {
1686 *s=0;
1687 break;
1688 }
1689 ++s;
1690 }
1691 if((*linePtr == 0) || (*linePtr == '#')) {
1692 continue; /* comment or empty line */
1693 }
1694
1695 /* Now, process the line */
1696 lineNext = NULL;
1697
1698 while(linePtr && *linePtr) { /* process space-separated items */
1699 while(*linePtr == ' ') {
1700 linePtr++;
1701 }
1702 /* Find the next quote */
1703 if(linePtr[0] == '"')
1704 {
1705 lineNext = uprv_strchr(linePtr+1, '"');
1706 if(lineNext == NULL) {
1707 fprintf(stderr, "%s:%d - missing trailing double quote (\")\n",
1708 l->str, (int)ln);
1709 exit(1);
1710 } else {
1711 lineNext++;
1712 if(*lineNext) {
1713 if(*lineNext != ' ') {
1714 fprintf(stderr, "%s:%d - malformed quoted line at position %d, expected ' ' got '%c'\n",
1715 l->str, (int)ln, (int)(lineNext-line), (*lineNext)?*lineNext:'0');
1716 exit(1);
1717 }
1718 *lineNext = 0;
1719 lineNext++;
1720 }
1721 }
1722 } else {
1723 lineNext = uprv_strchr(linePtr, ' ');
1724 if(lineNext) {
1725 *lineNext = 0; /* terminate at space */
1726 lineNext++;
1727 }
1728 }
1729
1730 /* add the file */
1731 s = (char*)getLongPathname(linePtr);
1732
1733 /* normal mode.. o->files is just the bare list without package names */
1734 o->files = pkg_appendToList(o->files, &tail, uprv_strdup(linePtr));
1735 if(uprv_pathIsAbsolute(s)) {
1736 fprintf(stderr, "pkgdata: Error: absolute path encountered. Old style paths are not supported. Use relative paths such as 'fur.res' or 'translit%cfur.res'.\n\tBad path: '%s'\n", U_FILE_SEP_CHAR, s);
1737 exit(U_ILLEGAL_ARGUMENT_ERROR);
1738 }
1739 uprv_strcpy(tmp, o->srcDir);
1740 uprv_strcat(tmp, o->srcDir[uprv_strlen(o->srcDir)-1] == U_FILE_SEP_CHAR ? "" :PKGDATA_FILE_SEP_STRING);
1741 uprv_strcat(tmp, s);
1742 o->filePaths = pkg_appendToList(o->filePaths, &tail2, uprv_strdup(tmp));
1743 linePtr = lineNext;
1744 } /* for each entry on line */
1745 } /* for each line */
1746 T_FileStream_close(in);
1747 } /* for each file list file */
1748 }
1749
1750 /* Try calling icu-config directly to get the option file. */
1751 static int32_t pkg_getOptionsFromICUConfig(UBool verbose, UOption *option) {
1752 #if U_HAVE_POPEN
1753 FILE *p = NULL;
1754 size_t n;
1755 static char buf[512] = "";
1756 char cmdBuf[1024];
1757 UErrorCode status = U_ZERO_ERROR;
1758 const char cmd[] = "icu-config --incpkgdatafile";
1759
1760 /* #1 try the same path where pkgdata was called from. */
1761 findDirname(progname, cmdBuf, 1024, &status);
1762 if(U_SUCCESS(status)) {
1763 uprv_strncat(cmdBuf, U_FILE_SEP_STRING, 1024);
1764 uprv_strncat(cmdBuf, cmd, 1024);
1765
1766 if(verbose) {
1767 fprintf(stdout, "# Calling icu-config: %s\n", cmdBuf);
1768 }
1769 p = popen(cmdBuf, "r");
1770 }
1771
1772 if(p == NULL) {
1773 if(verbose) {
1774 fprintf(stdout, "# Calling icu-config: %s\n", cmd);
1775 }
1776 p = popen(cmd, "r");
1777 }
1778
1779 if(p == NULL)
1780 {
1781 fprintf(stderr, "%s: icu-config: No icu-config found. (fix PATH or use -O option)\n", progname);
1782 return -1;
1783 }
1784
1785 n = fread(buf, 1, 511, p);
1786
1787 pclose(p);
1788
1789 if(n<=0)
1790 {
1791 fprintf(stderr,"%s: icu-config: Could not read from icu-config. (fix PATH or use -O option)\n", progname);
1792 return -1;
1793 }
1794
1795 for (int32_t length = strlen(buf) - 1; length >= 0; length--) {
1796 if (buf[length] == '\n' || buf[length] == ' ') {
1797 buf[length] = 0;
1798 } else {
1799 break;
1800 }
1801 }
1802
1803 if(buf[strlen(buf)-1]=='\n')
1804 {
1805 buf[strlen(buf)-1]=0;
1806 }
1807
1808 if(buf[0] == 0)
1809 {
1810 fprintf(stderr, "%s: icu-config: invalid response from icu-config (fix PATH or use -O option)\n", progname);
1811 return -1;
1812 }
1813
1814 if(verbose) {
1815 fprintf(stdout, "# icu-config said: %s\n", buf);
1816 }
1817
1818 option->value = buf;
1819 option->doesOccur = TRUE;
1820
1821 return 0;
1822 #endif
1823 return -1;
1824 }