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