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)
12 * created on: 2000may15
13 * created by: Steven \u24C7 Loomis
15 * This program packages the ICU data into different forms
16 * (DLL, common data, etc.)
19 // Defines _XOPEN_SOURCE for access to POSIX functions.
20 // Must be before any other #includes.
21 #include "uposixdefs.h"
23 #include "unicode/utypes.h"
25 #include "unicode/putil.h"
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__
39 #include "unicode/uclean.h"
45 #include "pkg_gencmn.h"
46 #include "flagparser.h"
47 #include "filetools.h"
63 using icu::LocalPointerBase;
65 U_DEFINE_LOCAL_OPEN_POINTER(LocalPipeFilePointer, FILE, pclose);
69 static void loadLists(UPKGOptions *o, UErrorCode *status);
71 static int32_t pkg_executeOptions(UPKGOptions *o);
73 #ifdef WINDOWS_WITH_MSVC
74 static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o);
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);
81 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
82 static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode);
85 #ifdef CAN_WRITE_OBJ_CODE
86 static void pkg_createOptMatchArch(char *optMatchArch);
87 static void pkg_destroyOptMatchArch(char *optMatchArch);
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);
96 static int32_t pkg_getOptionsFromICUConfig(UBool verbose, UOption *option);
97 static int runCommand(const char* command, UBool specialHandling=FALSE);
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')
127 /* This sets the modes that are available */
129 const char *name, *alt_name;
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 }
138 #ifdef UDATA_SO_SUFFIX
139 { "dll", "library", "Generates one shared library, <package>" UDATA_SO_SUFFIX },
141 { "common", "archive", "Generates one common data file, <package>.dat" },
142 { "static", "static", "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
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)
169 /* This enum and the following char array should be kept in sync. */
171 GENCCODE_ASSEMBLY_TYPE,
190 static const char* FLAG_NAMES[PKGDATA_FLAGS_SIZE] = {
191 "GENCCODE_ASSEMBLY_TYPE",
209 static char **pkgDataFlags = NULL;
213 LIB_FILE_VERSION_MAJOR,
215 LIB_FILE_VERSION_TMP,
216 #if U_PLATFORM == U_PF_CYGWIN
218 LIB_FILE_CYGWIN_VERSION,
219 #elif U_PLATFORM == U_PF_MINGW
221 #elif U_PLATFORM == U_PF_OS390
222 LIB_FILE_OS390BATCH_MAJOR,
223 LIB_FILE_OS390BATCH_VERSION,
227 static char libFileNames[LIB_FILENAMES_SIZE][256];
229 static UPKGOptions *pkg_checkFlag(UPKGOptions *o);
231 const char options_help[][320]={
233 #ifdef U_MAKE_IS_NMAKE
234 "The directory where the ICU is located (e.g. <ICUROOT> which contains the bin directory)",
236 "Specify options for the builder.",
238 "Specify the mode of building (see below; default: common)",
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)"
258 const char *progname = "PKGDATA";
261 main(int argc, char* argv[]) {
263 /* FileStream *out; */
266 UBool needsHelp = FALSE;
267 UErrorCode status = U_ZERO_ERROR;
268 /* char tmp[1024]; */
272 U_MAIN_INIT_ARGS(argc, argv);
276 options[MODE].value = "common";
278 /* read command line options */
279 argc=u_parseArgs(argc, argv, UPRV_LENGTHOF(options), options);
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. */
285 if(options[HELP].doesOccur || options[HELP_QUESTION_MARK].doesOccur) {
289 if(!needsHelp && argc<0) {
291 "%s: error in command line argument \"%s\"\n",
294 fprintf(stderr, "Run '%s --help' for help.\n", progname);
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);
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");
313 if(!options[NAME].doesOccur) /* -O we already have - don't report it. */
315 fprintf(stderr, " required parameter -p is missing \n");
316 fprintf(stderr, "Run '%s --help' for help.\n", progname);
322 "No input files specified.\n"
323 "Run '%s --help' for help.\n", progname);
326 } /* end !needsHelp */
328 if(argc<0 || needsHelp ) {
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",
336 fprintf(stderr, "\n options:\n");
337 for(i=0;i<UPRV_LENGTHOF(options);i++) {
338 fprintf(stderr, "%-5s -%c %s%-10s %s\n",
340 options[i].shortName,
341 options[i].longName ? "or --" : " ",
342 options[i].longName ? options[i].longName : "",
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);
352 fprintf(stderr, " ");
354 fprintf(stderr, " %s\n", modes[i].desc);
359 /* OK, fill in the options struct */
360 uprv_memset(&o, 0, sizeof(o));
362 o.mode = options[MODE].value;
363 o.version = options[REVISION].doesOccur ? options[REVISION].value : 0;
365 o.shortName = options[NAME].value;
367 int32_t len = (int32_t)uprv_strlen(o.shortName);
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 : '_';
380 o.cShortName = csname;
383 if(options[LIBNAME].doesOccur) { /* get libname from shortname, or explicit -L parameter */
384 o.libName = options[LIBNAME].value;
386 o.libName = o.shortName;
389 if(options[QUIET].doesOccur) {
395 if(options[PDS_BUILD].doesOccur) {
396 #if U_PLATFORM == U_PF_OS390
400 fprintf(stdout, "Warning: You are using the -z option which only works on z/OS.\n");
407 o.verbose = options[VERBOSE].doesOccur;
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;
417 if(options[COPYRIGHT].doesOccur) {
418 o.comment = U_COPYRIGHT_STRING;
419 } else if (options[COMMENT].doesOccur) {
420 o.comment = options[COMMENT].value;
423 if( options[DESTDIR].doesOccur ) {
424 o.targetDir = options[DESTDIR].value;
426 o.targetDir = "."; /* cwd */
429 o.rebuild = options[REBUILD].doesOccur;
431 if( options[TEMPDIR].doesOccur ) {
432 o.tmpDir = options[TEMPDIR].value;
434 o.tmpDir = o.targetDir;
437 if( options[INSTALL].doesOccur ) {
438 o.install = options[INSTALL].value;
443 if( options[SOURCEDIR].doesOccur ) {
444 o.srcDir = options[SOURCEDIR].value;
449 if( options[ENTRYPOINT].doesOccur ) {
450 o.entryName = options[ENTRYPOINT].value;
452 o.entryName = o.cShortName;
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");
461 o.withoutAssembly = TRUE;
465 /* OK options are set up. Now the file lists. */
467 for( n=1; n<argc; n++) {
468 o.fileListFiles = pkg_appendToList(o.fileListFiles, &tail, uprv_strdup(argv[n]));
472 loadLists(&o, &status);
473 if( U_FAILURE(status) ) {
474 fprintf(stderr, "error loading input file lists: %s\n", u_errorName(status));
478 result = pkg_executeOptions(&o);
480 if (pkgDataFlags != NULL) {
481 for (n = 0; n < PKGDATA_FLAGS_SIZE; n++) {
482 if (pkgDataFlags[n] != NULL) {
483 uprv_free(pkgDataFlags[n]);
486 uprv_free(pkgDataFlags);
489 if (o.cShortName != NULL) {
490 uprv_free((char *)o.cShortName);
492 if (o.fileListFiles != NULL) {
493 pkg_deleteList(o.fileListFiles);
495 if (o.filePaths != NULL) {
496 pkg_deleteList(o.filePaths);
498 if (o.files != NULL) {
499 pkg_deleteList(o.files);
505 static int runCommand(const char* command, UBool specialHandling) {
507 char cmdBuffer[SMALL_BUFFER_MAX_SIZE];
508 int32_t len = strlen(command);
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);
521 #if defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW
522 sprintf(cmd, "bash -c \"%s\"", command);
524 #elif U_PLATFORM == U_PF_OS400
525 sprintf(cmd, "QSH CMD('%s')", command);
528 goto normal_command_mode;
531 #if !(defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW || U_PLATFORM == U_PF_OS400)
534 cmd = (char *)command;
537 printf("pkgdata: %s\n", cmd);
538 int result = system(cmd);
540 fprintf(stderr, "-- return status = %d\n", result);
543 if (cmd != cmdBuffer && cmd != command) {
550 #define LN_CMD "ln -s"
551 #define RM_CMD "rm -f"
553 static int32_t pkg_executeOptions(UPKGOptions *o) {
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] = "";
563 initializePkgDataFlags(o);
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);
575 fprintf(stdout, "# Install: Files mode, copying files to %s..\n", targetDir);
577 result = pkg_installFileMode(targetDir, o->srcDir, o->fileListFiles->str);
580 } else /* if (IN_COMMON_MODE(mode) || IN_DLL_MODE(mode) || IN_STATIC_MODE(mode)) */ {
581 UBool noVersion = FALSE;
583 uprv_strcpy(targetDir, o->targetDir);
584 uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING);
586 uprv_strcpy(tmpDir, o->tmpDir);
587 uprv_strcat(tmpDir, PKGDATA_FILE_SEP_STRING);
589 uprv_strcpy(datFileNamePath, tmpDir);
591 uprv_strcpy(datFileName, o->shortName);
592 uprv_strcat(datFileName, UDATA_CMN_SUFFIX);
594 uprv_strcat(datFileNamePath, datFileName);
597 fprintf(stdout, "# Writing package file %s ..\n", datFileNamePath);
599 result = writePackageDatFile(datFileNamePath, o->comment, o->srcDir, o->fileListFiles->str, NULL, U_CHARSET_FAMILY ? 'e' : U_IS_BIG_ENDIAN ? 'b' : 'l');
601 fprintf(stderr,"Error writing package dat file.\n");
605 if (IN_COMMON_MODE(mode)) {
606 char targetFileNamePath[LARGE_BUFFER_MAX_SIZE] = "";
608 uprv_strcpy(targetFileNamePath, targetDir);
609 uprv_strcat(targetFileNamePath, datFileName);
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",
621 result = rename(datFileNamePath, targetFileNamePath);
624 fprintf(stdout, "# Moving package file to %s ..\n",
630 "Unable to move dat file (%s) to target location (%s).\n",
631 datFileNamePath, targetFileNamePath);
636 if (o->install != NULL) {
637 result = pkg_installCommonMode(o->install, targetFileNamePath);
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;
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;
654 version_major[i] = o->version[i];
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");
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.
667 if (pkgDataFlags[LIB_EXT_ORDER][uprv_strlen(pkgDataFlags[LIB_EXT_ORDER])-1] == pkgDataFlags[SO_EXT][uprv_strlen(pkgDataFlags[SO_EXT])-1]) {
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);
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) {
681 fprintf(stdout, "# Installing already-built library into %s\n", o->install);
683 result = pkg_installLibrary(o->install, targetDir, noVersion);
686 printf("# Not rebuilding %s - up to date.\n", checkLibFile);
690 } else if (o->verbose && (o->install!=NULL)) {
691 fprintf(stdout, "# Not installing up-to-date library %s into %s\n", checkLibFile, o->install);
693 } else if(o->verbose && (o->install!=NULL)) {
694 fprintf(stdout, "# Not installing missing %s into %s\n", checkLibFile, o->install);
698 if (pkg_checkFlag(o) == NULL) {
699 /* Error occurred. */
704 if (!o->withoutAssembly && pkgDataFlags[GENCCODE_ASSEMBLY_TYPE][0] != 0) {
705 const char* genccodeAssembly = pkgDataFlags[GENCCODE_ASSEMBLY_TYPE];
708 fprintf(stdout, "# Generating assembly code %s of type %s ..\n", gencFilePath, genccodeAssembly);
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);
717 result = pkg_createWithAssemblyCode(targetDir, mode, gencFilePath);
719 fprintf(stderr, "Error generating assembly code for data.\n");
721 } else if (IN_STATIC_MODE(mode)) {
722 if(o->install != NULL) {
724 fprintf(stdout, "# Installing static library into %s\n", o->install);
726 result = pkg_installLibrary(o->install, targetDir, noVersion);
731 fprintf(stderr,"Assembly type \"%s\" is unknown.\n", genccodeAssembly);
736 fprintf(stdout, "# Writing object code to %s ..\n", gencFilePath);
738 if (o->withoutAssembly) {
739 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
740 result = pkg_createWithoutAssemblyCode(o, targetDir, mode);
742 /* This error should not occur. */
743 fprintf(stderr, "Error- BUILD_DATA_WITHOUT_ASSEMBLY is not defined. Internal error.\n");
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);
757 #elif defined(BUILD_DATA_WITHOUT_ASSEMBLY)
758 result = pkg_createWithoutAssemblyCode(o, targetDir, mode);
760 fprintf(stderr, "Error- neither CAN_WRITE_OBJ_CODE nor BUILD_DATA_WITHOUT_ASSEMBLY are defined. Internal error.\n");
766 fprintf(stderr, "Error generating package data.\n");
770 #if !U_PLATFORM_USES_ONLY_WIN32_API
771 if(!IN_STATIC_MODE(mode)) {
772 /* Certain platforms uses archive library. (e.g. AIX) */
774 fprintf(stdout, "# Creating data archive library file ..\n");
776 result = pkg_archiveLibrary(targetDir, o->version, reverseExt);
778 fprintf(stderr, "Error creating data archive library file.\n");
781 #if U_PLATFORM != U_PF_OS400
783 /* Create symbolic links for the final library file. */
784 #if U_PLATFORM == U_PF_OS390
785 result = pkg_createSymLinks(targetDir, o->pdsbuild);
787 result = pkg_createSymLinks(targetDir, noVersion);
790 fprintf(stderr, "Error creating symbolic links of the data library file.\n");
795 } /* !IN_STATIC_MODE */
798 #if !U_PLATFORM_USES_ONLY_WIN32_API
799 /* Install the libraries if option was set. */
800 if (o->install != NULL) {
802 fprintf(stdout, "# Installing library file to %s ..\n", o->install);
804 result = pkg_installLibrary(o->install, targetDir, noVersion);
806 fprintf(stderr, "Error installing the data library.\n");
816 /* Initialize the pkgDataFlags with the option file given. */
817 static int32_t initializePkgDataFlags(UPKGOptions *o) {
818 UErrorCode status = U_ZERO_ERROR;
820 int32_t currentBufferSize = SMALL_BUFFER_MAX_SIZE;
821 int32_t tmpResult = 0;
823 /* Initialize pkgdataFlags */
824 pkgDataFlags = (char**)uprv_malloc(sizeof(char*) * PKGDATA_FLAGS_SIZE);
826 /* If we run out of space, allocate more */
827 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
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;
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;
845 fprintf(stderr,"Error allocating memory for pkgDataFlags.\n");
849 if (o->options == NULL) {
853 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
854 /* Read in options file. */
856 fprintf(stdout, "# Reading options file %s\n", o->options);
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;
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));
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]);
878 fprintf(stdout, "\n");
880 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
881 } while (status == U_BUFFER_OVERFLOW_ERROR);
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.
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] == '.' ? "." : "";
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);
901 sprintf(libFileNames[LIB_FILE], "%s%s",
902 pkgDataFlags[LIBPREFIX],
906 sprintf(libFileNames[LIB_FILE], "%s%s",
907 pkgDataFlags[LIBPREFIX],
912 fprintf(stdout, "# libFileName[LIB_FILE] = %s\n", libFileNames[LIB_FILE]);
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",
922 pkgDataFlags[SO_EXT]);
923 sprintf(libFileNames[LIB_FILE_CYGWIN_VERSION], "cyg%s%s%s%s",
927 pkgDataFlags[SO_EXT]);
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],
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],
942 reverseExt ? pkgDataFlags[SOBJ_EXT] : version);
944 sprintf(libFileNames[LIB_FILE_OS390BATCH_VERSION], "%s%s.x",
945 libFileNames[LIB_FILE],
947 sprintf(libFileNames[LIB_FILE_OS390BATCH_MAJOR], "%s%s.x",
948 libFileNames[LIB_FILE],
951 if (noVersion && !reverseExt) {
952 sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s",
953 libFileNames[LIB_FILE],
955 pkgDataFlags[SOBJ_EXT]);
957 sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s%s%s",
958 libFileNames[LIB_FILE],
960 reverseExt ? version : pkgDataFlags[SOBJ_EXT],
962 reverseExt ? pkgDataFlags[SOBJ_EXT] : version);
965 if (noVersion && !reverseExt) {
966 sprintf(libFileNames[LIB_FILE_VERSION_MAJOR], "%s%s%s",
967 libFileNames[LIB_FILE],
969 pkgDataFlags[SO_EXT]);
971 sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s",
972 libFileNames[LIB_FILE],
974 pkgDataFlags[SO_EXT]);
976 sprintf(libFileNames[LIB_FILE_VERSION_MAJOR], "%s%s%s%s%s",
977 libFileNames[LIB_FILE],
979 reverseExt ? version_major : pkgDataFlags[SO_EXT],
981 reverseExt ? pkgDataFlags[SO_EXT] : version_major);
983 sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s%s%s",
984 libFileNames[LIB_FILE],
986 reverseExt ? version : pkgDataFlags[SO_EXT],
988 reverseExt ? pkgDataFlags[SO_EXT] : version);
992 fprintf(stdout, "# libFileName[LIB_FILE_VERSION] = %s\n", libFileNames[LIB_FILE_VERSION]);
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]);
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;
1004 fprintf(stdout, "# libFileName[LIB_FILE_VERSION] = %s (static)\n", libFileNames[LIB_FILE_VERSION]);
1009 /* Create the symbolic links for the final library file. */
1010 static int32_t pkg_createSymLinks(const char *targetDir, UBool specialHandling) {
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 ? "" : ".";
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) {
1024 sprintf(cmd, "cd %s && %s %s && %s %s %s",
1027 libFileNames[LIB_FILE_VERSION_MAJOR],
1029 libFileNames[LIB_FILE_VERSION],
1030 libFileNames[LIB_FILE_VERSION_MAJOR]);
1031 result = runCommand(cmd);
1033 fprintf(stderr, "Error creating symbolic links. Failed command: %s\n", cmd);
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",
1050 libFileNames[LIB_FILE_OS390BATCH_MAJOR],
1052 libFileNames[LIB_FILE_OS390BATCH_VERSION],
1053 libFileNames[LIB_FILE_OS390BATCH_MAJOR]);
1054 result = runCommand(cmd);
1056 fprintf(stderr, "Error creating symbolic links. Failed command: %s\n", cmd);
1060 sprintf(cmd, "cd %s && %s %s.x && %s %s %s.x",
1063 libFileNames[LIB_FILE],
1065 libFileNames[LIB_FILE_OS390BATCH_VERSION],
1066 libFileNames[LIB_FILE]);
1067 result = runCommand(cmd);
1069 fprintf(stderr, "Error creating symbolic links. Failed command: %s\n", cmd);
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]);
1078 goto normal_symlink_mode;
1081 #if U_PLATFORM != U_PF_CYGWIN
1082 normal_symlink_mode:
1084 sprintf(name1, "%s%s%s", libFileNames[LIB_FILE], FILE_EXTENSION_SEP, pkgDataFlags[SO_EXT]);
1085 sprintf(name2, "%s", libFileNames[LIB_FILE_VERSION]);
1088 sprintf(cmd, "cd %s && %s %s && %s %s %s",
1096 result = runCommand(cmd);
1101 static int32_t pkg_installLibrary(const char *installDir, const char *targetDir, UBool noVersion) {
1103 char cmd[SMALL_BUFFER_MAX_SIZE];
1105 sprintf(cmd, "cd %s && %s %s %s%s%s",
1107 pkgDataFlags[INSTALL_CMD],
1108 libFileNames[LIB_FILE_VERSION],
1109 installDir, PKGDATA_FILE_SEP_STRING, libFileNames[LIB_FILE_VERSION]
1112 result = runCommand(cmd);
1115 fprintf(stderr, "Error installing library. Failed command: %s\n", cmd);
1120 sprintf(cmd, "cd %s && %s %s.lib %s",
1122 pkgDataFlags[INSTALL_CMD],
1123 libFileNames[LIB_FILE],
1126 result = runCommand(cmd);
1129 fprintf(stderr, "Error installing library. Failed command: %s\n", cmd);
1132 #elif U_PLATFORM == U_PF_CYGWIN
1133 sprintf(cmd, "cd %s && %s %s %s",
1135 pkgDataFlags[INSTALL_CMD],
1136 libFileNames[LIB_FILE_CYGWIN_VERSION],
1139 result = runCommand(cmd);
1142 fprintf(stderr, "Error installing library. Failed command: %s\n", cmd);
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],
1153 result = runCommand(cmd);
1156 fprintf(stderr, "Error installing library. Failed command: %s\n", cmd);
1165 return pkg_createSymLinks(installDir, TRUE);
1169 static int32_t pkg_installCommonMode(const char *installDir, const char *fileName) {
1171 char cmd[SMALL_BUFFER_MAX_SIZE] = "";
1173 if (!T_FileStream_file_exists(installDir)) {
1174 UErrorCode status = U_ZERO_ERROR;
1176 uprv_mkdir(installDir, &status);
1177 if (U_FAILURE(status)) {
1178 fprintf(stderr, "Error creating installation directory: %s\n", installDir);
1182 #ifndef U_WINDOWS_WITH_MSVC
1183 sprintf(cmd, "%s %s %s", pkgDataFlags[INSTALL_CMD], fileName, installDir);
1185 sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, fileName, installDir, WIN_INSTALL_CMD_FLAGS);
1188 result = runCommand(cmd);
1190 fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
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"
1201 static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName) {
1203 char cmd[SMALL_BUFFER_MAX_SIZE] = "";
1205 if (!T_FileStream_file_exists(installDir)) {
1206 UErrorCode status = U_ZERO_ERROR;
1208 uprv_mkdir(installDir, &status);
1209 if (U_FAILURE(status)) {
1210 fprintf(stderr, "Error creating installation directory: %s\n", installDir);
1214 #ifndef U_WINDOWS_WITH_MSVC
1215 char buffer[SMALL_BUFFER_MAX_SIZE] = "";
1216 int32_t bufferLength = 0;
1218 FileStream *f = T_FileStream_open(fileListName, "r");
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;
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);
1233 result = runCommand(cmd);
1235 fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
1239 if (!T_FileStream_eof(f)) {
1240 fprintf(stderr, "Failed to read line from file: %s\n", fileListName);
1246 T_FileStream_close(f);
1249 fprintf(stderr, "Unable to open list file: %s\n", fileListName);
1252 sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, srcDir, installDir, WIN_INSTALL_CMD_FLAGS);
1253 result = runCommand(cmd);
1255 fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
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.
1265 static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt) {
1267 char cmd[LARGE_BUFFER_MAX_SIZE];
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.
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);
1279 sprintf(cmd, "%s %s %s%s %s%s",
1281 pkgDataFlags[ARFLAGS],
1283 libFileNames[LIB_FILE_VERSION],
1285 libFileNames[LIB_FILE_VERSION_TMP]);
1287 result = runCommand(cmd);
1289 fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd);
1293 sprintf(cmd, "%s %s%s",
1294 pkgDataFlags[RANLIB],
1296 libFileNames[LIB_FILE_VERSION]);
1298 result = runCommand(cmd);
1300 fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd);
1304 /* Remove unneeded library file. */
1305 sprintf(cmd, "%s %s%s",
1308 libFileNames[LIB_FILE_VERSION_TMP]);
1310 result = runCommand(cmd);
1312 fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd);
1317 uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]);
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.
1327 static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command, UBool specialHandling) {
1330 UBool freeCmd = FALSE;
1333 (void)specialHandling; // Suppress unused variable compiler warnings on platforms where all usage
1334 // of this parameter is #ifdefed out.
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.
1340 if (command != NULL) {
1344 if (IN_STATIC_MODE(mode)) {
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");
1354 sprintf(cmd, "%s %s %s%s %s",
1356 pkgDataFlags[ARFLAGS],
1358 libFileNames[LIB_FILE_VERSION],
1361 result = runCommand(cmd);
1363 sprintf(cmd, "%s %s%s",
1364 pkgDataFlags[RANLIB],
1366 libFileNames[LIB_FILE_VERSION]);
1368 result = runCommand(cmd);
1370 } else /* if (IN_DLL_MODE(mode)) */ {
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]);
1382 if ((cmd = (char *)uprv_malloc(sizeof(char) * length)) == NULL) {
1383 fprintf(stderr, "Unable to allocate memory for command.\n");
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],
1392 libFileNames[LIB_FILE_MINGW],
1393 pkgDataFlags[LDICUDTFLAGS],
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],
1400 libFileNames[LIB_FILE_VERSION_TMP],
1401 pkgDataFlags[LDICUDTFLAGS],
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",
1408 libFileNames[LIB_FILE_VERSION_TMP],
1409 pkgDataFlags[GENLIB],
1410 pkgDataFlags[LDICUDTFLAGS],
1412 libFileNames[LIB_FILE_VERSION_TMP],
1414 sprintf(cmd, "%s %s -o %s%s %s %s%s %s %s",
1415 pkgDataFlags[GENLIB],
1416 pkgDataFlags[LDICUDTFLAGS],
1418 libFileNames[LIB_FILE_VERSION_TMP],
1421 pkgDataFlags[LD_SONAME],
1422 pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR],
1423 pkgDataFlags[RPATH_FLAGS],
1424 pkgDataFlags[BIR_FLAGS]);
1426 /* Generate the library file. */
1427 result = runCommand(cmd);
1429 #if U_PLATFORM == U_PF_OS390
1431 char PDS_LibName[512];
1436 if (specialHandling && uprv_strcmp(libFileNames[LIB_FILE],"libicudata") == 0) {
1437 if (env_tmp = getenv("ICU_PDS_NAME")) {
1438 sprintf(PDS_Name, "%s%s",
1441 strcat(PDS_Name, getenv("ICU_PDS_NAME_SUFFIX"));
1442 } else if (env_tmp = getenv("PDS_NAME_PREFIX")) {
1443 sprintf(PDS_Name, "%s%s",
1445 U_ICU_VERSION_SHORT "DA");
1447 sprintf(PDS_Name, "%s%s",
1449 U_ICU_VERSION_SHORT "DA");
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",
1456 strcat(PDS_Name, getenv("ICU_PDS_NAME_SUFFIX"));
1457 } else if (env_tmp = getenv("PDS_NAME_PREFIX")) {
1458 sprintf(PDS_Name, "%s%s",
1460 U_ICU_VERSION_SHORT "D1");
1462 sprintf(PDS_Name, "%s%s",
1464 U_ICU_VERSION_SHORT "D1");
1469 sprintf(PDS_LibName,"%s%s%s%s%s",
1475 sprintf(cmd, "%s %s -o %s %s %s%s %s %s",
1476 pkgDataFlags[GENLIB],
1477 pkgDataFlags[LDICUDTFLAGS],
1480 pkgDataFlags[LD_SONAME],
1481 pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR],
1482 pkgDataFlags[RPATH_FLAGS],
1483 pkgDataFlags[BIR_FLAGS]);
1485 result = runCommand(cmd);
1491 fprintf(stderr, "Error generating library file. Failed command: %s\n", cmd);
1501 static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath) {
1502 char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
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';
1512 length = uprv_strlen(pkgDataFlags[COMPILER]) + uprv_strlen(pkgDataFlags[LIBFLAGS])
1513 + uprv_strlen(tempObjectFile) + uprv_strlen(gencFilePath) + BUFFER_PADDING_SIZE;
1515 cmd = (char *)uprv_malloc(sizeof(char) * length);
1520 /* Generate the object file. */
1521 sprintf(cmd, "%s %s -o %s %s",
1522 pkgDataFlags[COMPILER],
1523 pkgDataFlags[LIBFLAGS],
1527 result = runCommand(cmd);
1530 fprintf(stderr, "Error creating with assembly code. Failed command: %s\n", cmd);
1534 return pkg_generateLibraryFile(targetDir, mode, tempObjectFile);
1537 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
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.
1550 DATA_PREFIX_TRANSLIT,
1556 const static char DATA_PREFIX[DATA_PREFIX_LENGTH][10] = {
1568 static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode) {
1570 CharList *list = o->filePaths;
1571 CharList *listNames = o->files;
1572 int32_t listSize = pkg_countCharList(list);
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;
1581 sprintf(icudtAll, "%s%s%sall.c",
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);
1591 if((icudtAllFile = T_FileStream_open(icudtAll, "w"))==NULL) {
1592 fprintf(stderr, "Unable to write to icudtall file: %s\n", icudtAll);
1597 if (list == NULL || listNames == NULL) {
1598 /* list and listNames should never be NULL since we are looping through the CharList with
1604 if ((cmd = (char *)uprv_malloc((listSize + 2) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
1605 fprintf(stderr, "Unable to allocate memory for cmd.\n");
1607 } else if ((buffer = (char *)uprv_malloc((listSize + 1) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
1608 fprintf(stderr, "Unable to allocate memory for buffer.\n");
1613 for (int32_t i = 0; i < (listSize + 1); i++) {
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);
1621 #ifdef USE_SINGLE_CCODE_FILE
1622 uprv_strcpy(tempObjectFile, gencmnFile);
1623 tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
1625 sprintf(cmd, "%s %s -o %s %s",
1626 pkgDataFlags[COMPILER],
1627 pkgDataFlags[LIBFLAGS],
1631 result = runCommand(cmd);
1636 sprintf(buffer, "%s",tempObjectFile);
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;
1644 name = listNames->str;
1646 newName[0] = dataName[0] = 0;
1647 for (int32_t n = 0; n < DATA_PREFIX_LENGTH; n++) {
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++) {
1657 newNameTmp[i] = '_';
1660 newNameTmp[i] = p[i];
1665 sprintf(newName, "%s_%s",
1668 sprintf(dataName, "%s_%s",
1672 if (newName[0] != 0) {
1678 printf("# Generating %s \n", gencmnFile);
1681 writeCCode(file, o->tmpDir, dataName[0] != 0 ? dataName : o->shortName, newName[0] != 0 ? newName : NULL, gencmnFile);
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 */
1690 #ifndef USE_SINGLE_CCODE_FILE
1691 uprv_strcpy(tempObjectFile, gencmnFile);
1692 tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
1694 sprintf(cmd, "%s %s -o %s %s",
1695 pkgDataFlags[COMPILER],
1696 pkgDataFlags[LIBFLAGS],
1699 result = runCommand(cmd);
1701 fprintf(stderr, "Error creating library without assembly code. Failed command: %s\n", cmd);
1705 uprv_strcat(buffer, " ");
1706 uprv_strcat(buffer, tempObjectFile);
1712 listNames = listNames->next;
1716 #ifdef USE_SINGLE_CCODE_FILE
1717 T_FileStream_close(icudtAllFile);
1718 uprv_strcpy(tempObjectFile, icudtAll);
1719 tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
1721 sprintf(cmd, "%s %s -I. -o %s %s",
1722 pkgDataFlags[COMPILER],
1723 pkgDataFlags[LIBFLAGS],
1727 result = runCommand(cmd);
1729 uprv_strcat(buffer, " ");
1730 uprv_strcat(buffer, tempObjectFile);
1732 fprintf(stderr, "Error creating library without assembly code. Failed command: %s\n", cmd);
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)));
1741 result = pkg_generateLibraryFile(targetDir,mode, buffer, cmd);
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
1760 static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o) {
1762 char cmd[LARGE_BUFFER_MAX_SIZE];
1763 if (IN_STATIC_MODE(mode)) {
1764 char staticLibFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1767 sprintf(staticLibFilePath, "%s%s%s%s%s",
1769 PKGDATA_FILE_SEP_STRING,
1770 pkgDataFlags[LIBPREFIX],
1774 sprintf(staticLibFilePath, "%s%s%s%s%s",
1776 PKGDATA_FILE_SEP_STRING,
1777 (strstr(o->libName, "icudt") ? "s" : ""),
1782 sprintf(cmd, "%s\"%s\" \"%s\"",
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] = "";
1793 uprv_strcpy(dllFilePath, o->targetDir);
1795 uprv_strcpy(dllFilePath, o->srcDir);
1797 uprv_strcat(dllFilePath, PKGDATA_FILE_SEP_STRING);
1798 uprv_strcpy(libFilePath, dllFilePath);
1801 uprv_strcat(libFilePath, o->libName);
1802 uprv_strcat(libFilePath, ".lib");
1804 uprv_strcat(dllFilePath, o->libName);
1805 uprv_strcat(dllFilePath, o->version);
1807 if (strstr(o->libName, "icudt")) {
1808 uprv_strcat(libFilePath, LIB_FILE);
1810 uprv_strcat(libFilePath, o->libName);
1811 uprv_strcat(libFilePath, ".lib");
1813 uprv_strcat(dllFilePath, o->entryName);
1815 uprv_strcat(dllFilePath, DLL_EXT);
1817 uprv_strcpy(tmpResFilePath, o->tmpDir);
1818 uprv_strcat(tmpResFilePath, PKGDATA_FILE_SEP_STRING);
1819 uprv_strcat(tmpResFilePath, ICUDATA_RES_FILE);
1821 if (T_FileStream_file_exists(tmpResFilePath)) {
1822 sprintf(resFilePath, "\"%s\"", tmpResFilePath);
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))) {
1829 printf("# Not rebuilding %s - up to date.\n", gencFilePath);
1834 sprintf(cmd, "%s\"%s\" %s\"%s\" \"%s\" %s",
1844 result = runCommand(cmd, TRUE);
1846 fprintf(stderr, "Error creating Windows DLL library. Failed command: %s\n", cmd);
1853 static UPKGOptions *pkg_checkFlag(UPKGOptions *o) {
1854 #if U_PLATFORM == U_PF_AIX
1855 /* AIX needs a map file. */
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] = "";
1864 const char rm_cmd[] = "rm -f all ;";
1866 flag = pkgDataFlags[GENLIB];
1868 /* This portion of the code removes 'rm -f all' in the GENLIB.
1869 * Only occurs in AIX.
1871 if (uprv_strstr(flag, rm_cmd) != NULL) {
1872 char *tmpGenlibFlagBuffer = NULL;
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);
1883 uprv_strcpy(tmpGenlibFlagBuffer, flag);
1885 offset = uprv_strlen(rm_cmd);
1887 for (i = 0; i < (length - offset); i++) {
1888 flag[i] = tmpGenlibFlagBuffer[offset + i];
1891 /* Zero terminate the string */
1894 uprv_free(tmpGenlibFlagBuffer);
1897 flag = pkgDataFlags[BIR_FLAGS];
1898 length = uprv_strlen(pkgDataFlags[BIR_FLAGS]);
1900 for (int32_t i = 0; i < length; i++) {
1901 if (flag[i] == MAP_FILE_EXT[count]) {
1910 if (count == uprv_strlen(MAP_FILE_EXT)) {
1917 for (int32_t i = 0;;i++) {
1919 for (int32_t n = 0;;n++) {
1920 if (o->shortName[n] == 0) {
1923 tmpbuffer[index++] = o->shortName[n];
1927 tmpbuffer[index++] = flag[i];
1934 uprv_memset(flag, 0, length);
1935 uprv_strcpy(flag, tmpbuffer);
1937 uprv_strcpy(mapFile, o->shortName);
1938 uprv_strcat(mapFile, MAP_FILE_EXT);
1940 f = T_FileStream_open(mapFile, "w");
1942 fprintf(stderr,"Unable to create map file: %s.\n", mapFile);
1945 sprintf(tmpbuffer, "%s%s ", o->entryName, UDATA_CMN_INTERMEDIATE_SUFFIX);
1947 T_FileStream_writeLine(f, tmpbuffer);
1949 T_FileStream_close(f);
1952 #elif U_PLATFORM == U_PF_CYGWIN || U_PLATFORM == U_PF_MINGW
1953 /* Cygwin needs to change flag options. */
1957 flag = pkgDataFlags[GENLIB];
1958 length = uprv_strlen(pkgDataFlags[GENLIB]);
1960 int32_t position = length - 1;
1962 for(;position >= 0;position--) {
1963 if (flag[position] == '=') {
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) */
1975 flag = pkgDataFlags[GENLIB];
1976 length = uprv_strlen(pkgDataFlags[GENLIB]);
1978 int32_t position = length - 1;
1980 for(int32_t i = 0; i < length; i++) {
1981 if (flag[i] == '\'') {
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.
1991 static void loadLists(UPKGOptions *o, UErrorCode *status)
1993 CharList *l, *tail = NULL, *tail2 = NULL;
1996 char *linePtr, *lineNext;
1997 const uint32_t lineMax = 16300;
1999 int32_t tmpLength = 0;
2001 int32_t ln=0; /* line number */
2003 for(l = o->fileListFiles; l; l = l->next) {
2005 fprintf(stdout, "# pkgdata: Reading %s..\n", l->str);
2008 in = T_FileStream_open(l->str, "r"); /* open files list */
2011 fprintf(stderr, "Error opening <%s>.\n", l->str);
2012 *status = U_FILE_ACCESS_ERROR;
2016 while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) { /* for each line */
2018 if(uprv_strlen(line)>lineMax) {
2019 fprintf(stderr, "%s:%d - line too long (over %d chars)\n", l->str, (int)ln, (int)lineMax);
2022 /* remove spaces at the beginning */
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)) {
2031 /* remove trailing newline characters */
2033 if(*s=='\r' || *s=='\n') {
2039 if((*linePtr == 0) || (*linePtr == '#')) {
2040 continue; /* comment or empty line */
2043 /* Now, process the line */
2046 while(linePtr && *linePtr) { /* process space-separated items */
2047 while(*linePtr == ' ') {
2050 /* Find the next quote */
2051 if(linePtr[0] == '"')
2053 lineNext = uprv_strchr(linePtr+1, '"');
2054 if(lineNext == NULL) {
2055 fprintf(stderr, "%s:%d - missing trailing double quote (\")\n",
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');
2071 lineNext = uprv_strchr(linePtr, ' ');
2073 *lineNext = 0; /* terminate at space */
2079 s = (char*)getLongPathname(linePtr);
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);
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);
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);
2098 } /* for each entry on line */
2099 } /* for each line */
2100 T_FileStream_close(in);
2101 } /* for each file list file */
2104 /* Try calling icu-config directly to get the option file. */
2105 static int32_t pkg_getOptionsFromICUConfig(UBool verbose, UOption *option) {
2107 LocalPipeFilePointer p;
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 );
2121 cmdBuf.append( cmd, status );
2124 fprintf(stdout, "# Calling icu-config: %s\n", cmdBuf.data());
2126 p.adoptInstead(popen(cmdBuf.data(), "r"));
2129 if(p.isNull() || (n = fread(buf, 1, UPRV_LENGTHOF(buf)-1, p.getAlias())) <= 0) {
2131 fprintf(stdout, "# Calling icu-config: %s\n", cmd);
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);
2141 for (int32_t length = strlen(buf) - 1; length >= 0; length--) {
2142 if (buf[length] == '\n' || buf[length] == ' ') {
2149 if(buf[strlen(buf)-1]=='\n')
2151 buf[strlen(buf)-1]=0;
2156 fprintf(stderr, "%s: icu-config: invalid response from icu-config (fix PATH or use -O option)\n", progname);
2161 fprintf(stdout, "# icu-config said: %s\n", buf);
2164 option->value = buf;
2165 option->doesOccur = TRUE;
2173 #ifdef CAN_WRITE_OBJ_CODE
2174 /* Create optMatchArch for genccode architecture detection */
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;
2182 stream = T_FileStream_open(source,"w");
2183 if (stream != NULL) {
2184 T_FileStream_writeLine(stream, code);
2185 T_FileStream_close(stream);
2187 char cmd[LARGE_BUFFER_MAX_SIZE];
2188 sprintf(cmd, "%s %s -o %s",
2189 pkgDataFlags[COMPILER],
2193 if (runCommand(cmd) == 0){
2194 sprintf(optMatchArch, "%s", obj);
2197 fprintf(stderr, "Failed to compile %s\n", source);
2199 if(!T_FileStream_remove(source)){
2200 fprintf(stderr, "T_FileStream_remove failed to delete %s\n", source);
2204 fprintf(stderr, "T_FileStream_open failed to open %s for writing\n", source);
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);