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 = static_cast<int32_t>(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%s",
908 (strstr(libName, "icudt") ? "lib" : ""),
909 pkgDataFlags[LIBPREFIX],
910 libName);
911 }
912 #else
913 sprintf(libFileNames[LIB_FILE], "%s%s",
914 pkgDataFlags[LIBPREFIX],
915 libName);
916 #endif
917
918 if(o->verbose) {
919 fprintf(stdout, "# libFileName[LIB_FILE] = %s\n", libFileNames[LIB_FILE]);
920 }
921
922 #if U_PLATFORM == U_PF_MINGW
923 // Name the import library lib*.dll.a
924 sprintf(libFileNames[LIB_FILE_MINGW], "lib%s.dll.a", libName);
925 #elif U_PLATFORM == U_PF_CYGWIN
926 sprintf(libFileNames[LIB_FILE_CYGWIN], "cyg%s%s%s",
927 libName,
928 FILE_EXTENSION_SEP,
929 pkgDataFlags[SO_EXT]);
930 sprintf(libFileNames[LIB_FILE_CYGWIN_VERSION], "cyg%s%s%s%s",
931 libName,
932 version_major,
933 FILE_EXTENSION_SEP,
934 pkgDataFlags[SO_EXT]);
935
936 uprv_strcat(pkgDataFlags[SO_EXT], ".");
937 uprv_strcat(pkgDataFlags[SO_EXT], pkgDataFlags[A_EXT]);
938 #elif U_PLATFORM == U_PF_OS400 || defined(_AIX)
939 sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s",
940 libFileNames[LIB_FILE],
941 FILE_EXTENSION_SEP,
942 pkgDataFlags[SOBJ_EXT]);
943 #elif U_PLATFORM == U_PF_OS390
944 sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s%s%s",
945 libFileNames[LIB_FILE],
946 pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
947 reverseExt ? version : pkgDataFlags[SOBJ_EXT],
948 FILE_EXTENSION_SEP,
949 reverseExt ? pkgDataFlags[SOBJ_EXT] : version);
950
951 sprintf(libFileNames[LIB_FILE_OS390BATCH_VERSION], "%s%s.x",
952 libFileNames[LIB_FILE],
953 version);
954 sprintf(libFileNames[LIB_FILE_OS390BATCH_MAJOR], "%s%s.x",
955 libFileNames[LIB_FILE],
956 version_major);
957 #else
958 if (noVersion && !reverseExt) {
959 sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s",
960 libFileNames[LIB_FILE],
961 FILE_SUFFIX,
962 pkgDataFlags[SOBJ_EXT]);
963 } else {
964 sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s%s%s",
965 libFileNames[LIB_FILE],
966 FILE_SUFFIX,
967 reverseExt ? version : pkgDataFlags[SOBJ_EXT],
968 FILE_EXTENSION_SEP,
969 reverseExt ? pkgDataFlags[SOBJ_EXT] : version);
970 }
971 #endif
972 if (noVersion && !reverseExt) {
973 sprintf(libFileNames[LIB_FILE_VERSION_MAJOR], "%s%s%s",
974 libFileNames[LIB_FILE],
975 FILE_SUFFIX,
976 pkgDataFlags[SO_EXT]);
977
978 sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s",
979 libFileNames[LIB_FILE],
980 FILE_SUFFIX,
981 pkgDataFlags[SO_EXT]);
982 } else {
983 sprintf(libFileNames[LIB_FILE_VERSION_MAJOR], "%s%s%s%s%s",
984 libFileNames[LIB_FILE],
985 FILE_SUFFIX,
986 reverseExt ? version_major : pkgDataFlags[SO_EXT],
987 FILE_EXTENSION_SEP,
988 reverseExt ? pkgDataFlags[SO_EXT] : version_major);
989
990 sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s%s%s",
991 libFileNames[LIB_FILE],
992 FILE_SUFFIX,
993 reverseExt ? version : pkgDataFlags[SO_EXT],
994 FILE_EXTENSION_SEP,
995 reverseExt ? pkgDataFlags[SO_EXT] : version);
996 }
997
998 if(o->verbose) {
999 fprintf(stdout, "# libFileName[LIB_FILE_VERSION] = %s\n", libFileNames[LIB_FILE_VERSION]);
1000 }
1001
1002 #if U_PF_MINGW <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
1003 /* Cygwin and MinGW only deals with the version major number. */
1004 uprv_strcpy(libFileNames[LIB_FILE_VERSION_TMP], libFileNames[LIB_FILE_VERSION_MAJOR]);
1005 #endif
1006
1007 if(IN_STATIC_MODE(mode)) {
1008 sprintf(libFileNames[LIB_FILE_VERSION], "%s.%s", libFileNames[LIB_FILE], pkgDataFlags[A_EXT]);
1009 libFileNames[LIB_FILE_VERSION_MAJOR][0]=0;
1010 if(o->verbose) {
1011 fprintf(stdout, "# libFileName[LIB_FILE_VERSION] = %s (static)\n", libFileNames[LIB_FILE_VERSION]);
1012 }
1013 }
1014 }
1015
1016 /* Create the symbolic links for the final library file. */
pkg_createSymLinks(const char * targetDir,UBool specialHandling)1017 static int32_t pkg_createSymLinks(const char *targetDir, UBool specialHandling) {
1018 int32_t result = 0;
1019 char cmd[LARGE_BUFFER_MAX_SIZE];
1020 char name1[SMALL_BUFFER_MAX_SIZE]; /* symlink file name */
1021 char name2[SMALL_BUFFER_MAX_SIZE]; /* file name to symlink */
1022 const char* FILE_EXTENSION_SEP = uprv_strlen(pkgDataFlags[SO_EXT]) == 0 ? "" : ".";
1023
1024 #if U_PLATFORM != U_PF_CYGWIN
1025 /* No symbolic link to make. */
1026 if (uprv_strlen(libFileNames[LIB_FILE_VERSION]) == 0 || uprv_strlen(libFileNames[LIB_FILE_VERSION_MAJOR]) == 0 ||
1027 uprv_strcmp(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_MAJOR]) == 0) {
1028 return result;
1029 }
1030
1031 sprintf(cmd, "cd %s && %s %s && %s %s %s",
1032 targetDir,
1033 RM_CMD,
1034 libFileNames[LIB_FILE_VERSION_MAJOR],
1035 LN_CMD,
1036 libFileNames[LIB_FILE_VERSION],
1037 libFileNames[LIB_FILE_VERSION_MAJOR]);
1038 result = runCommand(cmd);
1039 if (result != 0) {
1040 fprintf(stderr, "Error creating symbolic links. Failed command: %s\n", cmd);
1041 return result;
1042 }
1043 #endif
1044
1045 if (specialHandling) {
1046 #if U_PLATFORM == U_PF_CYGWIN
1047 sprintf(name1, "%s", libFileNames[LIB_FILE_CYGWIN]);
1048 sprintf(name2, "%s", libFileNames[LIB_FILE_CYGWIN_VERSION]);
1049 #elif U_PLATFORM == U_PF_OS390
1050 /* Create the symbolic links for the import data */
1051 /* Use the cmd buffer to store path to import data file to check its existence */
1052 sprintf(cmd, "%s/%s", targetDir, libFileNames[LIB_FILE_OS390BATCH_VERSION]);
1053 if (T_FileStream_file_exists(cmd)) {
1054 sprintf(cmd, "cd %s && %s %s && %s %s %s",
1055 targetDir,
1056 RM_CMD,
1057 libFileNames[LIB_FILE_OS390BATCH_MAJOR],
1058 LN_CMD,
1059 libFileNames[LIB_FILE_OS390BATCH_VERSION],
1060 libFileNames[LIB_FILE_OS390BATCH_MAJOR]);
1061 result = runCommand(cmd);
1062 if (result != 0) {
1063 fprintf(stderr, "Error creating symbolic links. Failed command: %s\n", cmd);
1064 return result;
1065 }
1066
1067 sprintf(cmd, "cd %s && %s %s.x && %s %s %s.x",
1068 targetDir,
1069 RM_CMD,
1070 libFileNames[LIB_FILE],
1071 LN_CMD,
1072 libFileNames[LIB_FILE_OS390BATCH_VERSION],
1073 libFileNames[LIB_FILE]);
1074 result = runCommand(cmd);
1075 if (result != 0) {
1076 fprintf(stderr, "Error creating symbolic links. Failed command: %s\n", cmd);
1077 return result;
1078 }
1079 }
1080
1081 /* Needs to be set here because special handling skips it */
1082 sprintf(name1, "%s%s%s", libFileNames[LIB_FILE], FILE_EXTENSION_SEP, pkgDataFlags[SO_EXT]);
1083 sprintf(name2, "%s", libFileNames[LIB_FILE_VERSION]);
1084 #else
1085 goto normal_symlink_mode;
1086 #endif
1087 } else {
1088 #if U_PLATFORM != U_PF_CYGWIN
1089 normal_symlink_mode:
1090 #endif
1091 sprintf(name1, "%s%s%s", libFileNames[LIB_FILE], FILE_EXTENSION_SEP, pkgDataFlags[SO_EXT]);
1092 sprintf(name2, "%s", libFileNames[LIB_FILE_VERSION]);
1093 }
1094
1095 sprintf(cmd, "cd %s && %s %s && %s %s %s",
1096 targetDir,
1097 RM_CMD,
1098 name1,
1099 LN_CMD,
1100 name2,
1101 name1);
1102
1103 result = runCommand(cmd);
1104
1105 return result;
1106 }
1107
pkg_installLibrary(const char * installDir,const char * targetDir,UBool noVersion)1108 static int32_t pkg_installLibrary(const char *installDir, const char *targetDir, UBool noVersion) {
1109 int32_t result = 0;
1110 char cmd[SMALL_BUFFER_MAX_SIZE];
1111
1112 sprintf(cmd, "cd %s && %s %s %s%s%s",
1113 targetDir,
1114 pkgDataFlags[INSTALL_CMD],
1115 libFileNames[LIB_FILE_VERSION],
1116 installDir, PKGDATA_FILE_SEP_STRING, libFileNames[LIB_FILE_VERSION]
1117 );
1118
1119 result = runCommand(cmd);
1120
1121 if (result != 0) {
1122 fprintf(stderr, "Error installing library. Failed command: %s\n", cmd);
1123 return result;
1124 }
1125
1126 #ifdef CYGWINMSVC
1127 sprintf(cmd, "cd %s && %s %s.lib %s",
1128 targetDir,
1129 pkgDataFlags[INSTALL_CMD],
1130 libFileNames[LIB_FILE],
1131 installDir
1132 );
1133 result = runCommand(cmd);
1134
1135 if (result != 0) {
1136 fprintf(stderr, "Error installing library. Failed command: %s\n", cmd);
1137 return result;
1138 }
1139 #elif U_PLATFORM == U_PF_CYGWIN
1140 sprintf(cmd, "cd %s && %s %s %s",
1141 targetDir,
1142 pkgDataFlags[INSTALL_CMD],
1143 libFileNames[LIB_FILE_CYGWIN_VERSION],
1144 installDir
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 #elif U_PLATFORM == U_PF_OS390
1154 if (T_FileStream_file_exists(libFileNames[LIB_FILE_OS390BATCH_VERSION])) {
1155 sprintf(cmd, "%s %s %s",
1156 pkgDataFlags[INSTALL_CMD],
1157 libFileNames[LIB_FILE_OS390BATCH_VERSION],
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 }
1167 #endif
1168
1169 if (noVersion) {
1170 return result;
1171 } else {
1172 return pkg_createSymLinks(installDir, TRUE);
1173 }
1174 }
1175
pkg_installCommonMode(const char * installDir,const char * fileName)1176 static int32_t pkg_installCommonMode(const char *installDir, const char *fileName) {
1177 int32_t result = 0;
1178 char cmd[SMALL_BUFFER_MAX_SIZE] = "";
1179
1180 if (!T_FileStream_file_exists(installDir)) {
1181 UErrorCode status = U_ZERO_ERROR;
1182
1183 uprv_mkdir(installDir, &status);
1184 if (U_FAILURE(status)) {
1185 fprintf(stderr, "Error creating installation directory: %s\n", installDir);
1186 return -1;
1187 }
1188 }
1189 #ifndef U_WINDOWS_WITH_MSVC
1190 sprintf(cmd, "%s %s %s", pkgDataFlags[INSTALL_CMD], fileName, installDir);
1191 #else
1192 sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, fileName, installDir, WIN_INSTALL_CMD_FLAGS);
1193 #endif
1194
1195 result = runCommand(cmd);
1196 if (result != 0) {
1197 fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
1198 }
1199
1200 return result;
1201 }
1202
1203 #ifdef U_WINDOWS_MSVC
1204 /* Copy commands for installing the raw data files on Windows. */
1205 #define WIN_INSTALL_CMD "xcopy"
1206 #define WIN_INSTALL_CMD_FLAGS "/E /Y /K"
1207 #endif
pkg_installFileMode(const char * installDir,const char * srcDir,const char * fileListName)1208 static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName) {
1209 int32_t result = 0;
1210 char cmd[SMALL_BUFFER_MAX_SIZE] = "";
1211
1212 if (!T_FileStream_file_exists(installDir)) {
1213 UErrorCode status = U_ZERO_ERROR;
1214
1215 uprv_mkdir(installDir, &status);
1216 if (U_FAILURE(status)) {
1217 fprintf(stderr, "Error creating installation directory: %s\n", installDir);
1218 return -1;
1219 }
1220 }
1221 #ifndef U_WINDOWS_WITH_MSVC
1222 char buffer[SMALL_BUFFER_MAX_SIZE] = "";
1223 int32_t bufferLength = 0;
1224
1225 FileStream *f = T_FileStream_open(fileListName, "r");
1226 if (f != NULL) {
1227 for(;;) {
1228 if (T_FileStream_readLine(f, buffer, SMALL_BUFFER_MAX_SIZE) != NULL) {
1229 bufferLength = static_cast<int32_t>(uprv_strlen(buffer));
1230 /* Remove new line character. */
1231 if (bufferLength > 0) {
1232 buffer[bufferLength-1] = 0;
1233 }
1234
1235 sprintf(cmd, "%s %s%s%s %s%s%s",
1236 pkgDataFlags[INSTALL_CMD],
1237 srcDir, PKGDATA_FILE_SEP_STRING, buffer,
1238 installDir, PKGDATA_FILE_SEP_STRING, buffer);
1239
1240 result = runCommand(cmd);
1241 if (result != 0) {
1242 fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
1243 break;
1244 }
1245 } else {
1246 if (!T_FileStream_eof(f)) {
1247 fprintf(stderr, "Failed to read line from file: %s\n", fileListName);
1248 result = -1;
1249 }
1250 break;
1251 }
1252 }
1253 T_FileStream_close(f);
1254 } else {
1255 result = -1;
1256 fprintf(stderr, "Unable to open list file: %s\n", fileListName);
1257 }
1258 #else
1259 sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, srcDir, installDir, WIN_INSTALL_CMD_FLAGS);
1260 result = runCommand(cmd);
1261 if (result != 0) {
1262 fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
1263 }
1264 #endif
1265
1266 return result;
1267 }
1268
1269 /* Archiving of the library file may be needed depending on the platform and options given.
1270 * If archiving is not needed, copy over the library file name.
1271 */
pkg_archiveLibrary(const char * targetDir,const char * version,UBool reverseExt)1272 static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt) {
1273 int32_t result = 0;
1274 char cmd[LARGE_BUFFER_MAX_SIZE];
1275
1276 /* If the shared object suffix and the final object suffix is different and the final object suffix and the
1277 * archive file suffix is the same, then the final library needs to be archived.
1278 */
1279 if (uprv_strcmp(pkgDataFlags[SOBJ_EXT], pkgDataFlags[SO_EXT]) != 0 && uprv_strcmp(pkgDataFlags[A_EXT], pkgDataFlags[SO_EXT]) == 0) {
1280 sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s.%s",
1281 libFileNames[LIB_FILE],
1282 pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
1283 reverseExt ? version : pkgDataFlags[SO_EXT],
1284 reverseExt ? pkgDataFlags[SO_EXT] : version);
1285
1286 sprintf(cmd, "%s %s %s%s %s%s",
1287 pkgDataFlags[AR],
1288 pkgDataFlags[ARFLAGS],
1289 targetDir,
1290 libFileNames[LIB_FILE_VERSION],
1291 targetDir,
1292 libFileNames[LIB_FILE_VERSION_TMP]);
1293
1294 result = runCommand(cmd);
1295 if (result != 0) {
1296 fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd);
1297 return result;
1298 }
1299
1300 sprintf(cmd, "%s %s%s",
1301 pkgDataFlags[RANLIB],
1302 targetDir,
1303 libFileNames[LIB_FILE_VERSION]);
1304
1305 result = runCommand(cmd);
1306 if (result != 0) {
1307 fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd);
1308 return result;
1309 }
1310
1311 /* Remove unneeded library file. */
1312 sprintf(cmd, "%s %s%s",
1313 RM_CMD,
1314 targetDir,
1315 libFileNames[LIB_FILE_VERSION_TMP]);
1316
1317 result = runCommand(cmd);
1318 if (result != 0) {
1319 fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd);
1320 return result;
1321 }
1322
1323 } else {
1324 uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]);
1325 }
1326
1327 return result;
1328 }
1329
1330 /*
1331 * Using the compiler information from the configuration file set by -O option, generate the library file.
1332 * command may be given to allow for a larger buffer for cmd.
1333 */
pkg_generateLibraryFile(const char * targetDir,const char mode,const char * objectFile,char * command,UBool specialHandling)1334 static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command, UBool specialHandling) {
1335 int32_t result = 0;
1336 char *cmd = NULL;
1337 UBool freeCmd = FALSE;
1338 int32_t length = 0;
1339
1340 (void)specialHandling; // Suppress unused variable compiler warnings on platforms where all usage
1341 // of this parameter is #ifdefed out.
1342
1343 /* This is necessary because if packaging is done without assembly code, objectFile might be extremely large
1344 * containing many object files and so the calling function should supply a command buffer that is large
1345 * enough to handle this. Otherwise, use the default size.
1346 */
1347 if (command != NULL) {
1348 cmd = command;
1349 }
1350
1351 if (IN_STATIC_MODE(mode)) {
1352 if (cmd == NULL) {
1353 length = uprv_strlen(pkgDataFlags[AR]) + uprv_strlen(pkgDataFlags[ARFLAGS]) + uprv_strlen(targetDir) +
1354 uprv_strlen(libFileNames[LIB_FILE_VERSION]) + uprv_strlen(objectFile) + uprv_strlen(pkgDataFlags[RANLIB]) + BUFFER_PADDING_SIZE;
1355 if ((cmd = (char *)uprv_malloc(sizeof(char) * length)) == NULL) {
1356 fprintf(stderr, "Unable to allocate memory for command.\n");
1357 return -1;
1358 }
1359 freeCmd = TRUE;
1360 }
1361 sprintf(cmd, "%s %s %s%s %s",
1362 pkgDataFlags[AR],
1363 pkgDataFlags[ARFLAGS],
1364 targetDir,
1365 libFileNames[LIB_FILE_VERSION],
1366 objectFile);
1367
1368 result = runCommand(cmd);
1369 if (result == 0) {
1370 sprintf(cmd, "%s %s%s",
1371 pkgDataFlags[RANLIB],
1372 targetDir,
1373 libFileNames[LIB_FILE_VERSION]);
1374
1375 result = runCommand(cmd);
1376 }
1377 } else /* if (IN_DLL_MODE(mode)) */ {
1378 if (cmd == NULL) {
1379 length = uprv_strlen(pkgDataFlags[GENLIB]) + uprv_strlen(pkgDataFlags[LDICUDTFLAGS]) +
1380 ((uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_VERSION_TMP])) * 2) +
1381 uprv_strlen(objectFile) + uprv_strlen(pkgDataFlags[LD_SONAME]) +
1382 uprv_strlen(pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR]) +
1383 uprv_strlen(pkgDataFlags[RPATH_FLAGS]) + uprv_strlen(pkgDataFlags[BIR_FLAGS]) + BUFFER_PADDING_SIZE;
1384 #if U_PLATFORM == U_PF_CYGWIN
1385 length += uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_CYGWIN_VERSION]);
1386 #elif U_PLATFORM == U_PF_MINGW
1387 length += uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_MINGW]);
1388 #endif
1389 if ((cmd = (char *)uprv_malloc(sizeof(char) * length)) == NULL) {
1390 fprintf(stderr, "Unable to allocate memory for command.\n");
1391 return -1;
1392 }
1393 freeCmd = TRUE;
1394 }
1395 #if U_PLATFORM == U_PF_MINGW
1396 sprintf(cmd, "%s%s%s %s -o %s%s %s %s%s %s %s",
1397 pkgDataFlags[GENLIB],
1398 targetDir,
1399 libFileNames[LIB_FILE_MINGW],
1400 pkgDataFlags[LDICUDTFLAGS],
1401 targetDir,
1402 libFileNames[LIB_FILE_VERSION_TMP],
1403 #elif U_PLATFORM == U_PF_CYGWIN
1404 sprintf(cmd, "%s%s%s %s -o %s%s %s %s%s %s %s",
1405 pkgDataFlags[GENLIB],
1406 targetDir,
1407 libFileNames[LIB_FILE_VERSION_TMP],
1408 pkgDataFlags[LDICUDTFLAGS],
1409 targetDir,
1410 libFileNames[LIB_FILE_CYGWIN_VERSION],
1411 #elif U_PLATFORM == U_PF_AIX
1412 sprintf(cmd, "%s %s%s;%s %s -o %s%s %s %s%s %s %s",
1413 RM_CMD,
1414 targetDir,
1415 libFileNames[LIB_FILE_VERSION_TMP],
1416 pkgDataFlags[GENLIB],
1417 pkgDataFlags[LDICUDTFLAGS],
1418 targetDir,
1419 libFileNames[LIB_FILE_VERSION_TMP],
1420 #else
1421 sprintf(cmd, "%s %s -o %s%s %s %s%s %s %s",
1422 pkgDataFlags[GENLIB],
1423 pkgDataFlags[LDICUDTFLAGS],
1424 targetDir,
1425 libFileNames[LIB_FILE_VERSION_TMP],
1426 #endif
1427 objectFile,
1428 pkgDataFlags[LD_SONAME],
1429 pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR],
1430 pkgDataFlags[RPATH_FLAGS],
1431 pkgDataFlags[BIR_FLAGS]);
1432
1433 /* Generate the library file. */
1434 result = runCommand(cmd);
1435
1436 #if U_PLATFORM == U_PF_OS390
1437 char *env_tmp;
1438 char PDS_LibName[512];
1439 char PDS_Name[512];
1440
1441 PDS_Name[0] = 0;
1442 PDS_LibName[0] = 0;
1443 if (specialHandling && uprv_strcmp(libFileNames[LIB_FILE],"libicudata") == 0) {
1444 if (env_tmp = getenv("ICU_PDS_NAME")) {
1445 sprintf(PDS_Name, "%s%s",
1446 env_tmp,
1447 "DA");
1448 strcat(PDS_Name, getenv("ICU_PDS_NAME_SUFFIX"));
1449 } else if (env_tmp = getenv("PDS_NAME_PREFIX")) {
1450 sprintf(PDS_Name, "%s%s",
1451 env_tmp,
1452 U_ICU_VERSION_SHORT "DA");
1453 } else {
1454 sprintf(PDS_Name, "%s%s",
1455 "IXMI",
1456 U_ICU_VERSION_SHORT "DA");
1457 }
1458 } else if (!specialHandling && uprv_strcmp(libFileNames[LIB_FILE],"libicudata_stub") == 0) {
1459 if (env_tmp = getenv("ICU_PDS_NAME")) {
1460 sprintf(PDS_Name, "%s%s",
1461 env_tmp,
1462 "D1");
1463 strcat(PDS_Name, getenv("ICU_PDS_NAME_SUFFIX"));
1464 } else if (env_tmp = getenv("PDS_NAME_PREFIX")) {
1465 sprintf(PDS_Name, "%s%s",
1466 env_tmp,
1467 U_ICU_VERSION_SHORT "D1");
1468 } else {
1469 sprintf(PDS_Name, "%s%s",
1470 "IXMI",
1471 U_ICU_VERSION_SHORT "D1");
1472 }
1473 }
1474
1475 if (PDS_Name[0]) {
1476 sprintf(PDS_LibName,"%s%s%s%s%s",
1477 "\"//'",
1478 getenv("LOADMOD"),
1479 "(",
1480 PDS_Name,
1481 ")'\"");
1482 sprintf(cmd, "%s %s -o %s %s %s%s %s %s",
1483 pkgDataFlags[GENLIB],
1484 pkgDataFlags[LDICUDTFLAGS],
1485 PDS_LibName,
1486 objectFile,
1487 pkgDataFlags[LD_SONAME],
1488 pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR],
1489 pkgDataFlags[RPATH_FLAGS],
1490 pkgDataFlags[BIR_FLAGS]);
1491
1492 result = runCommand(cmd);
1493 }
1494 #endif
1495 }
1496
1497 if (result != 0) {
1498 fprintf(stderr, "Error generating library file. Failed command: %s\n", cmd);
1499 }
1500
1501 if (freeCmd) {
1502 uprv_free(cmd);
1503 }
1504
1505 return result;
1506 }
1507
pkg_createWithAssemblyCode(const char * targetDir,const char mode,const char * gencFilePath)1508 static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath) {
1509 char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
1510 char *cmd;
1511 int32_t result = 0;
1512
1513 int32_t length = 0;
1514
1515 /* Remove the ending .s and replace it with .o for the new object file. */
1516 uprv_strcpy(tempObjectFile, gencFilePath);
1517 tempObjectFile[uprv_strlen(tempObjectFile)-1] = 'o';
1518
1519 length = uprv_strlen(pkgDataFlags[COMPILER]) + uprv_strlen(pkgDataFlags[LIBFLAGS])
1520 + uprv_strlen(tempObjectFile) + uprv_strlen(gencFilePath) + BUFFER_PADDING_SIZE;
1521
1522 cmd = (char *)uprv_malloc(sizeof(char) * length);
1523 if (cmd == NULL) {
1524 return -1;
1525 }
1526
1527 /* Generate the object file. */
1528 sprintf(cmd, "%s %s -o %s %s",
1529 pkgDataFlags[COMPILER],
1530 pkgDataFlags[LIBFLAGS],
1531 tempObjectFile,
1532 gencFilePath);
1533
1534 result = runCommand(cmd);
1535 uprv_free(cmd);
1536 if (result != 0) {
1537 fprintf(stderr, "Error creating with assembly code. Failed command: %s\n", cmd);
1538 return result;
1539 }
1540
1541 return pkg_generateLibraryFile(targetDir, mode, tempObjectFile);
1542 }
1543
1544 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
1545 /*
1546 * Generation of the data library without assembly code needs to compile each data file
1547 * individually and then link it all together.
1548 * Note: Any update to the directory structure of the data needs to be reflected here.
1549 */
1550 enum {
1551 DATA_PREFIX_BRKITR,
1552 DATA_PREFIX_COLL,
1553 DATA_PREFIX_CURR,
1554 DATA_PREFIX_LANG,
1555 DATA_PREFIX_RBNF,
1556 DATA_PREFIX_REGION,
1557 DATA_PREFIX_TRANSLIT,
1558 DATA_PREFIX_ZONE,
1559 DATA_PREFIX_UNIT,
1560 DATA_PREFIX_LENGTH
1561 };
1562
1563 const static char DATA_PREFIX[DATA_PREFIX_LENGTH][10] = {
1564 "brkitr",
1565 "coll",
1566 "curr",
1567 "lang",
1568 "rbnf",
1569 "region",
1570 "translit",
1571 "zone",
1572 "unit"
1573 };
1574
pkg_createWithoutAssemblyCode(UPKGOptions * o,const char * targetDir,const char mode)1575 static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode) {
1576 int32_t result = 0;
1577 CharList *list = o->filePaths;
1578 CharList *listNames = o->files;
1579 int32_t listSize = pkg_countCharList(list);
1580 char *buffer;
1581 char *cmd;
1582 char gencmnFile[SMALL_BUFFER_MAX_SIZE] = "";
1583 char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
1584 #ifdef USE_SINGLE_CCODE_FILE
1585 char icudtAll[SMALL_BUFFER_MAX_SIZE] = "";
1586 FileStream *icudtAllFile = NULL;
1587
1588 sprintf(icudtAll, "%s%s%sall.c",
1589 o->tmpDir,
1590 PKGDATA_FILE_SEP_STRING,
1591 libFileNames[LIB_FILE]);
1592 /* Remove previous icudtall.c file. */
1593 if (T_FileStream_file_exists(icudtAll) && (result = remove(icudtAll)) != 0) {
1594 fprintf(stderr, "Unable to remove old icudtall file: %s\n", icudtAll);
1595 return result;
1596 }
1597
1598 if((icudtAllFile = T_FileStream_open(icudtAll, "w"))==NULL) {
1599 fprintf(stderr, "Unable to write to icudtall file: %s\n", icudtAll);
1600 return result;
1601 }
1602 #endif
1603
1604 if (list == NULL || listNames == NULL) {
1605 /* list and listNames should never be NULL since we are looping through the CharList with
1606 * the given size.
1607 */
1608 return -1;
1609 }
1610
1611 if ((cmd = (char *)uprv_malloc((listSize + 2) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
1612 fprintf(stderr, "Unable to allocate memory for cmd.\n");
1613 return -1;
1614 } else if ((buffer = (char *)uprv_malloc((listSize + 1) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
1615 fprintf(stderr, "Unable to allocate memory for buffer.\n");
1616 uprv_free(cmd);
1617 return -1;
1618 }
1619
1620 for (int32_t i = 0; i < (listSize + 1); i++) {
1621 const char *file ;
1622 const char *name;
1623
1624 if (i == 0) {
1625 /* The first iteration calls the gencmn function and initailizes the buffer. */
1626 createCommonDataFile(o->tmpDir, o->shortName, o->entryName, NULL, o->srcDir, o->comment, o->fileListFiles->str, 0, TRUE, o->verbose, gencmnFile);
1627 buffer[0] = 0;
1628 #ifdef USE_SINGLE_CCODE_FILE
1629 uprv_strcpy(tempObjectFile, gencmnFile);
1630 tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
1631
1632 sprintf(cmd, "%s %s -o %s %s",
1633 pkgDataFlags[COMPILER],
1634 pkgDataFlags[LIBFLAGS],
1635 tempObjectFile,
1636 gencmnFile);
1637
1638 result = runCommand(cmd);
1639 if (result != 0) {
1640 break;
1641 }
1642
1643 sprintf(buffer, "%s",tempObjectFile);
1644 #endif
1645 } else {
1646 char newName[SMALL_BUFFER_MAX_SIZE];
1647 char dataName[SMALL_BUFFER_MAX_SIZE];
1648 char dataDirName[SMALL_BUFFER_MAX_SIZE];
1649 const char *pSubstring;
1650 file = list->str;
1651 name = listNames->str;
1652
1653 newName[0] = dataName[0] = 0;
1654 for (int32_t n = 0; n < DATA_PREFIX_LENGTH; n++) {
1655 dataDirName[0] = 0;
1656 sprintf(dataDirName, "%s%s", DATA_PREFIX[n], PKGDATA_FILE_SEP_STRING);
1657 /* If the name contains a prefix (indicating directory), alter the new name accordingly. */
1658 pSubstring = uprv_strstr(name, dataDirName);
1659 if (pSubstring != NULL) {
1660 char newNameTmp[SMALL_BUFFER_MAX_SIZE] = "";
1661 const char *p = name + uprv_strlen(dataDirName);
1662 for (int32_t i = 0;;i++) {
1663 if (p[i] == '.') {
1664 newNameTmp[i] = '_';
1665 continue;
1666 }
1667 newNameTmp[i] = p[i];
1668 if (p[i] == 0) {
1669 break;
1670 }
1671 }
1672 sprintf(newName, "%s_%s",
1673 DATA_PREFIX[n],
1674 newNameTmp);
1675 sprintf(dataName, "%s_%s",
1676 o->shortName,
1677 DATA_PREFIX[n]);
1678 }
1679 if (newName[0] != 0) {
1680 break;
1681 }
1682 }
1683
1684 if(o->verbose) {
1685 printf("# Generating %s \n", gencmnFile);
1686 }
1687
1688 writeCCode(file, o->tmpDir, dataName[0] != 0 ? dataName : o->shortName, newName[0] != 0 ? newName : NULL, gencmnFile);
1689
1690 #ifdef USE_SINGLE_CCODE_FILE
1691 sprintf(cmd, "#include \"%s\"\n", gencmnFile);
1692 T_FileStream_writeLine(icudtAllFile, cmd);
1693 /* don't delete the file */
1694 #endif
1695 }
1696
1697 #ifndef USE_SINGLE_CCODE_FILE
1698 uprv_strcpy(tempObjectFile, gencmnFile);
1699 tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
1700
1701 sprintf(cmd, "%s %s -o %s %s",
1702 pkgDataFlags[COMPILER],
1703 pkgDataFlags[LIBFLAGS],
1704 tempObjectFile,
1705 gencmnFile);
1706 result = runCommand(cmd);
1707 if (result != 0) {
1708 fprintf(stderr, "Error creating library without assembly code. Failed command: %s\n", cmd);
1709 break;
1710 }
1711
1712 uprv_strcat(buffer, " ");
1713 uprv_strcat(buffer, tempObjectFile);
1714
1715 #endif
1716
1717 if (i > 0) {
1718 list = list->next;
1719 listNames = listNames->next;
1720 }
1721 }
1722
1723 #ifdef USE_SINGLE_CCODE_FILE
1724 T_FileStream_close(icudtAllFile);
1725 uprv_strcpy(tempObjectFile, icudtAll);
1726 tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
1727
1728 sprintf(cmd, "%s %s -I. -o %s %s",
1729 pkgDataFlags[COMPILER],
1730 pkgDataFlags[LIBFLAGS],
1731 tempObjectFile,
1732 icudtAll);
1733
1734 result = runCommand(cmd);
1735 if (result == 0) {
1736 uprv_strcat(buffer, " ");
1737 uprv_strcat(buffer, tempObjectFile);
1738 } else {
1739 fprintf(stderr, "Error creating library without assembly code. Failed command: %s\n", cmd);
1740 }
1741 #endif
1742
1743 if (result == 0) {
1744 /* Generate the library file. */
1745 #if U_PLATFORM == U_PF_OS390
1746 result = pkg_generateLibraryFile(targetDir, mode, buffer, cmd, (o->pdsbuild && IN_DLL_MODE(mode)));
1747 #else
1748 result = pkg_generateLibraryFile(targetDir,mode, buffer, cmd);
1749 #endif
1750 }
1751
1752 uprv_free(buffer);
1753 uprv_free(cmd);
1754
1755 return result;
1756 }
1757 #endif
1758
1759 #ifdef WINDOWS_WITH_MSVC
1760 #define LINK_CMD "link.exe /nologo /release /out:"
1761 #define LINK_FLAGS "/DLL /NOENTRY /MANIFEST:NO /implib:"
1762 #ifdef _WIN64
1763 #define LINK_EXTRA_UWP_FLAGS "/NXCOMPAT /DYNAMICBASE /APPCONTAINER "
1764 #else
1765 #define LINK_EXTRA_UWP_FLAGS "/NXCOMPAT /SAFESEH /DYNAMICBASE /APPCONTAINER /MACHINE:X86"
1766 #endif
1767 #define LINK_EXTRA_UWP_FLAGS_ARM "/NXCOMPAT /DYNAMICBASE /APPCONTAINER /MACHINE:ARM"
1768 #define LINK_EXTRA_NO_UWP_FLAGS "/base:0x4ad00000 "
1769 #define LIB_CMD "LIB.exe /nologo /out:"
1770 #define LIB_FILE "icudt.lib"
1771 #define LIB_EXT UDATA_LIB_SUFFIX
1772 #define DLL_EXT UDATA_SO_SUFFIX
1773
pkg_createWindowsDLL(const char mode,const char * gencFilePath,UPKGOptions * o)1774 static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o) {
1775 int32_t result = 0;
1776 char cmd[LARGE_BUFFER_MAX_SIZE];
1777 if (IN_STATIC_MODE(mode)) {
1778 char staticLibFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1779
1780 #ifdef CYGWINMSVC
1781 sprintf(staticLibFilePath, "%s%s%s%s%s",
1782 o->targetDir,
1783 PKGDATA_FILE_SEP_STRING,
1784 pkgDataFlags[LIBPREFIX],
1785 o->libName,
1786 LIB_EXT);
1787 #else
1788 sprintf(staticLibFilePath, "%s%s%s%s%s",
1789 o->targetDir,
1790 PKGDATA_FILE_SEP_STRING,
1791 (strstr(o->libName, "icudt") ? "s" : ""),
1792 o->libName,
1793 LIB_EXT);
1794 #endif
1795
1796 sprintf(cmd, "%s\"%s\" \"%s\"",
1797 LIB_CMD,
1798 staticLibFilePath,
1799 gencFilePath);
1800 } else if (IN_DLL_MODE(mode)) {
1801 char dllFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1802 char libFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1803 char resFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1804 char tmpResFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1805
1806 #ifdef CYGWINMSVC
1807 uprv_strcpy(dllFilePath, o->targetDir);
1808 #else
1809 uprv_strcpy(dllFilePath, o->srcDir);
1810 #endif
1811 uprv_strcat(dllFilePath, PKGDATA_FILE_SEP_STRING);
1812 uprv_strcpy(libFilePath, dllFilePath);
1813
1814 #ifdef CYGWINMSVC
1815 uprv_strcat(libFilePath, o->libName);
1816 uprv_strcat(libFilePath, ".lib");
1817
1818 uprv_strcat(dllFilePath, o->libName);
1819 uprv_strcat(dllFilePath, o->version);
1820 #else
1821 if (strstr(o->libName, "icudt")) {
1822 uprv_strcat(libFilePath, LIB_FILE);
1823 } else {
1824 uprv_strcat(libFilePath, o->libName);
1825 uprv_strcat(libFilePath, ".lib");
1826 }
1827 uprv_strcat(dllFilePath, o->entryName);
1828 #endif
1829 uprv_strcat(dllFilePath, DLL_EXT);
1830
1831 uprv_strcpy(tmpResFilePath, o->tmpDir);
1832 uprv_strcat(tmpResFilePath, PKGDATA_FILE_SEP_STRING);
1833 uprv_strcat(tmpResFilePath, ICUDATA_RES_FILE);
1834
1835 if (T_FileStream_file_exists(tmpResFilePath)) {
1836 sprintf(resFilePath, "\"%s\"", tmpResFilePath);
1837 }
1838
1839 /* Check if dll file and lib file exists and that it is not newer than genc file. */
1840 if (!o->rebuild && (T_FileStream_file_exists(dllFilePath) && isFileModTimeLater(dllFilePath, gencFilePath)) &&
1841 (T_FileStream_file_exists(libFilePath) && isFileModTimeLater(libFilePath, gencFilePath))) {
1842 if(o->verbose) {
1843 printf("# Not rebuilding %s - up to date.\n", gencFilePath);
1844 }
1845 return 0;
1846 }
1847
1848 char *extraFlags = "";
1849 #ifdef WINDOWS_WITH_MSVC
1850 if (options[UWP_BUILD].doesOccur)
1851 {
1852 if (options[UWP_ARM_BUILD].doesOccur)
1853 {
1854 extraFlags = LINK_EXTRA_UWP_FLAGS_ARM;
1855 }
1856 else
1857 {
1858 extraFlags = LINK_EXTRA_UWP_FLAGS;
1859 }
1860 }
1861 else
1862 {
1863 extraFlags = LINK_EXTRA_NO_UWP_FLAGS;
1864 }
1865 #endif
1866 sprintf(cmd, "%s\"%s\" %s %s\"%s\" \"%s\" %s",
1867 LINK_CMD,
1868 dllFilePath,
1869 extraFlags,
1870 LINK_FLAGS,
1871 libFilePath,
1872 gencFilePath,
1873 resFilePath
1874 );
1875 }
1876
1877 result = runCommand(cmd, TRUE);
1878 if (result != 0) {
1879 fprintf(stderr, "Error creating Windows DLL library. Failed command: %s\n", cmd);
1880 }
1881
1882 return result;
1883 }
1884 #endif
1885
pkg_checkFlag(UPKGOptions * o)1886 static UPKGOptions *pkg_checkFlag(UPKGOptions *o) {
1887 #if U_PLATFORM == U_PF_AIX
1888 /* AIX needs a map file. */
1889 char *flag = NULL;
1890 int32_t length = 0;
1891 char tmpbuffer[SMALL_BUFFER_MAX_SIZE];
1892 const char MAP_FILE_EXT[] = ".map";
1893 FileStream *f = NULL;
1894 char mapFile[SMALL_BUFFER_MAX_SIZE] = "";
1895 int32_t start = -1;
1896 uint32_t count = 0;
1897 const char rm_cmd[] = "rm -f all ;";
1898
1899 flag = pkgDataFlags[GENLIB];
1900
1901 /* This portion of the code removes 'rm -f all' in the GENLIB.
1902 * Only occurs in AIX.
1903 */
1904 if (uprv_strstr(flag, rm_cmd) != NULL) {
1905 char *tmpGenlibFlagBuffer = NULL;
1906 int32_t i, offset;
1907
1908 length = uprv_strlen(flag) + 1;
1909 tmpGenlibFlagBuffer = (char *)uprv_malloc(length);
1910 if (tmpGenlibFlagBuffer == NULL) {
1911 /* Memory allocation error */
1912 fprintf(stderr,"Unable to allocate buffer of size: %d.\n", length);
1913 return NULL;
1914 }
1915
1916 uprv_strcpy(tmpGenlibFlagBuffer, flag);
1917
1918 offset = uprv_strlen(rm_cmd);
1919
1920 for (i = 0; i < (length - offset); i++) {
1921 flag[i] = tmpGenlibFlagBuffer[offset + i];
1922 }
1923
1924 /* Zero terminate the string */
1925 flag[i] = 0;
1926
1927 uprv_free(tmpGenlibFlagBuffer);
1928 }
1929
1930 flag = pkgDataFlags[BIR_FLAGS];
1931 length = uprv_strlen(pkgDataFlags[BIR_FLAGS]);
1932
1933 for (int32_t i = 0; i < length; i++) {
1934 if (flag[i] == MAP_FILE_EXT[count]) {
1935 if (count == 0) {
1936 start = i;
1937 }
1938 count++;
1939 } else {
1940 count = 0;
1941 }
1942
1943 if (count == uprv_strlen(MAP_FILE_EXT)) {
1944 break;
1945 }
1946 }
1947
1948 if (start >= 0) {
1949 int32_t index = 0;
1950 for (int32_t i = 0;;i++) {
1951 if (i == start) {
1952 for (int32_t n = 0;;n++) {
1953 if (o->shortName[n] == 0) {
1954 break;
1955 }
1956 tmpbuffer[index++] = o->shortName[n];
1957 }
1958 }
1959
1960 tmpbuffer[index++] = flag[i];
1961
1962 if (flag[i] == 0) {
1963 break;
1964 }
1965 }
1966
1967 uprv_memset(flag, 0, length);
1968 uprv_strcpy(flag, tmpbuffer);
1969
1970 uprv_strcpy(mapFile, o->shortName);
1971 uprv_strcat(mapFile, MAP_FILE_EXT);
1972
1973 f = T_FileStream_open(mapFile, "w");
1974 if (f == NULL) {
1975 fprintf(stderr,"Unable to create map file: %s.\n", mapFile);
1976 return NULL;
1977 } else {
1978 sprintf(tmpbuffer, "%s%s ", o->entryName, UDATA_CMN_INTERMEDIATE_SUFFIX);
1979
1980 T_FileStream_writeLine(f, tmpbuffer);
1981
1982 T_FileStream_close(f);
1983 }
1984 }
1985 #elif U_PLATFORM == U_PF_CYGWIN || U_PLATFORM == U_PF_MINGW
1986 /* Cygwin needs to change flag options. */
1987 char *flag = NULL;
1988 int32_t length = 0;
1989
1990 flag = pkgDataFlags[GENLIB];
1991 length = uprv_strlen(pkgDataFlags[GENLIB]);
1992
1993 int32_t position = length - 1;
1994
1995 for(;position >= 0;position--) {
1996 if (flag[position] == '=') {
1997 position++;
1998 break;
1999 }
2000 }
2001
2002 uprv_memset(flag + position, 0, length - position);
2003 #elif U_PLATFORM == U_PF_OS400
2004 /* OS/400 needs to fix the ld options (swap single quote with double quote) */
2005 char *flag = NULL;
2006 int32_t length = 0;
2007
2008 flag = pkgDataFlags[GENLIB];
2009 length = uprv_strlen(pkgDataFlags[GENLIB]);
2010
2011 int32_t position = length - 1;
2012
2013 for(int32_t i = 0; i < length; i++) {
2014 if (flag[i] == '\'') {
2015 flag[i] = '\"';
2016 }
2017 }
2018 #endif
2019 // Don't really need a return value, just need to stop compiler warnings about
2020 // the unused parameter 'o' on platforms where it is not otherwise used.
2021 return o;
2022 }
2023
loadLists(UPKGOptions * o,UErrorCode * status)2024 static void loadLists(UPKGOptions *o, UErrorCode *status)
2025 {
2026 CharList *l, *tail = NULL, *tail2 = NULL;
2027 FileStream *in;
2028 char line[16384];
2029 char *linePtr, *lineNext;
2030 const uint32_t lineMax = 16300;
2031 char *tmp;
2032 int32_t tmpLength = 0;
2033 char *s;
2034 int32_t ln=0; /* line number */
2035
2036 for(l = o->fileListFiles; l; l = l->next) {
2037 if(o->verbose) {
2038 fprintf(stdout, "# pkgdata: Reading %s..\n", l->str);
2039 }
2040 /* TODO: stdin */
2041 in = T_FileStream_open(l->str, "r"); /* open files list */
2042
2043 if(!in) {
2044 fprintf(stderr, "Error opening <%s>.\n", l->str);
2045 *status = U_FILE_ACCESS_ERROR;
2046 return;
2047 }
2048
2049 while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) { /* for each line */
2050 ln++;
2051 if(uprv_strlen(line)>lineMax) {
2052 fprintf(stderr, "%s:%d - line too long (over %d chars)\n", l->str, (int)ln, (int)lineMax);
2053 exit(1);
2054 }
2055 /* remove spaces at the beginning */
2056 linePtr = line;
2057 /* On z/OS, disable call to isspace (#9996). Investigate using uprv_isspace instead (#9999) */
2058 #if U_PLATFORM != U_PF_OS390
2059 while(isspace(*linePtr)) {
2060 linePtr++;
2061 }
2062 #endif
2063 s=linePtr;
2064 /* remove trailing newline characters */
2065 while(*s!=0) {
2066 if(*s=='\r' || *s=='\n') {
2067 *s=0;
2068 break;
2069 }
2070 ++s;
2071 }
2072 if((*linePtr == 0) || (*linePtr == '#')) {
2073 continue; /* comment or empty line */
2074 }
2075
2076 /* Now, process the line */
2077 lineNext = NULL;
2078
2079 while(linePtr && *linePtr) { /* process space-separated items */
2080 while(*linePtr == ' ') {
2081 linePtr++;
2082 }
2083 /* Find the next quote */
2084 if(linePtr[0] == '"')
2085 {
2086 lineNext = uprv_strchr(linePtr+1, '"');
2087 if(lineNext == NULL) {
2088 fprintf(stderr, "%s:%d - missing trailing double quote (\")\n",
2089 l->str, (int)ln);
2090 exit(1);
2091 } else {
2092 lineNext++;
2093 if(*lineNext) {
2094 if(*lineNext != ' ') {
2095 fprintf(stderr, "%s:%d - malformed quoted line at position %d, expected ' ' got '%c'\n",
2096 l->str, (int)ln, (int)(lineNext-line), (*lineNext)?*lineNext:'0');
2097 exit(1);
2098 }
2099 *lineNext = 0;
2100 lineNext++;
2101 }
2102 }
2103 } else {
2104 lineNext = uprv_strchr(linePtr, ' ');
2105 if(lineNext) {
2106 *lineNext = 0; /* terminate at space */
2107 lineNext++;
2108 }
2109 }
2110
2111 /* add the file */
2112 s = (char*)getLongPathname(linePtr);
2113
2114 /* normal mode.. o->files is just the bare list without package names */
2115 o->files = pkg_appendToList(o->files, &tail, uprv_strdup(linePtr));
2116 if(uprv_pathIsAbsolute(s) || s[0] == '.') {
2117 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);
2118 exit(U_ILLEGAL_ARGUMENT_ERROR);
2119 }
2120 tmpLength = uprv_strlen(o->srcDir) +
2121 uprv_strlen(s) + 5; /* 5 is to add a little extra space for, among other things, PKGDATA_FILE_SEP_STRING */
2122 if((tmp = (char *)uprv_malloc(tmpLength)) == NULL) {
2123 fprintf(stderr, "pkgdata: Error: Unable to allocate tmp buffer size: %d\n", tmpLength);
2124 exit(U_MEMORY_ALLOCATION_ERROR);
2125 }
2126 uprv_strcpy(tmp, o->srcDir);
2127 uprv_strcat(tmp, o->srcDir[uprv_strlen(o->srcDir)-1] == U_FILE_SEP_CHAR ? "" : PKGDATA_FILE_SEP_STRING);
2128 uprv_strcat(tmp, s);
2129 o->filePaths = pkg_appendToList(o->filePaths, &tail2, tmp);
2130 linePtr = lineNext;
2131 } /* for each entry on line */
2132 } /* for each line */
2133 T_FileStream_close(in);
2134 } /* for each file list file */
2135 }
2136
2137 /* Try calling icu-config directly to get the option file. */
pkg_getOptionsFromICUConfig(UBool verbose,UOption * option)2138 static int32_t pkg_getOptionsFromICUConfig(UBool verbose, UOption *option) {
2139 #if U_HAVE_POPEN
2140 LocalPipeFilePointer p;
2141 size_t n;
2142 static char buf[512] = "";
2143 icu::CharString cmdBuf;
2144 UErrorCode status = U_ZERO_ERROR;
2145 const char cmd[] = "icu-config --incpkgdatafile";
2146 char dirBuf[1024] = "";
2147 /* #1 try the same path where pkgdata was called from. */
2148 findDirname(progname, dirBuf, UPRV_LENGTHOF(dirBuf), &status);
2149 if(U_SUCCESS(status)) {
2150 cmdBuf.append(dirBuf, status);
2151 if (cmdBuf[0] != 0) {
2152 cmdBuf.append( U_FILE_SEP_STRING, status );
2153 }
2154 cmdBuf.append( cmd, status );
2155
2156 if(verbose) {
2157 fprintf(stdout, "# Calling icu-config: %s\n", cmdBuf.data());
2158 }
2159 p.adoptInstead(popen(cmdBuf.data(), "r"));
2160 }
2161
2162 if(p.isNull() || (n = fread(buf, 1, UPRV_LENGTHOF(buf)-1, p.getAlias())) <= 0) {
2163 if(verbose) {
2164 fprintf(stdout, "# Calling icu-config: %s\n", cmd);
2165 }
2166
2167 p.adoptInstead(popen(cmd, "r"));
2168 if(p.isNull() || (n = fread(buf, 1, UPRV_LENGTHOF(buf)-1, p.getAlias())) <= 0) {
2169 fprintf(stderr, "%s: icu-config: No icu-config found. (fix PATH or use -O option)\n", progname);
2170 return -1;
2171 }
2172 }
2173
2174 for (int32_t length = strlen(buf) - 1; length >= 0; length--) {
2175 if (buf[length] == '\n' || buf[length] == ' ') {
2176 buf[length] = 0;
2177 } else {
2178 break;
2179 }
2180 }
2181
2182 if(buf[strlen(buf)-1]=='\n')
2183 {
2184 buf[strlen(buf)-1]=0;
2185 }
2186
2187 if(buf[0] == 0)
2188 {
2189 fprintf(stderr, "%s: icu-config: invalid response from icu-config (fix PATH or use -O option)\n", progname);
2190 return -1;
2191 }
2192
2193 if(verbose) {
2194 fprintf(stdout, "# icu-config said: %s\n", buf);
2195 }
2196
2197 option->value = buf;
2198 option->doesOccur = TRUE;
2199
2200 return 0;
2201 #else
2202 return -1;
2203 #endif
2204 }
2205
2206 #ifdef CAN_WRITE_OBJ_CODE
2207 /* Create optMatchArch for genccode architecture detection */
pkg_createOptMatchArch(char * optMatchArch)2208 static void pkg_createOptMatchArch(char *optMatchArch) {
2209 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
2210 const char* code = "void oma(){}";
2211 const char* source = "oma.c";
2212 const char* obj = "oma.obj";
2213 FileStream* stream = NULL;
2214
2215 stream = T_FileStream_open(source,"w");
2216 if (stream != NULL) {
2217 T_FileStream_writeLine(stream, code);
2218 T_FileStream_close(stream);
2219
2220 char cmd[LARGE_BUFFER_MAX_SIZE];
2221 sprintf(cmd, "%s %s -o %s",
2222 pkgDataFlags[COMPILER],
2223 source,
2224 obj);
2225
2226 if (runCommand(cmd) == 0){
2227 sprintf(optMatchArch, "%s", obj);
2228 }
2229 else {
2230 fprintf(stderr, "Failed to compile %s\n", source);
2231 }
2232 if(!T_FileStream_remove(source)){
2233 fprintf(stderr, "T_FileStream_remove failed to delete %s\n", source);
2234 }
2235 }
2236 else {
2237 fprintf(stderr, "T_FileStream_open failed to open %s for writing\n", source);
2238 }
2239 #endif
2240 }
pkg_destroyOptMatchArch(char * optMatchArch)2241 static void pkg_destroyOptMatchArch(char *optMatchArch) {
2242 if(T_FileStream_file_exists(optMatchArch) && !T_FileStream_remove(optMatchArch)){
2243 fprintf(stderr, "T_FileStream_remove failed to delete %s\n", optMatchArch);
2244 }
2245 }
2246 #endif
2247