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