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