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