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