| // © 2016 and later: Unicode, Inc. and others. | |
| // License & terms of use: http://www.unicode.org/copyright.html | |
| /****************************************************************************** | |
| * Copyright (C) 2000-2016, International Business Machines | |
| * Corporation and others. All Rights Reserved. | |
| ******************************************************************************* | |
| * file name: pkgdata.cpp | |
| * encoding: ANSI X3.4 (1968) | |
| * tab size: 8 (not used) | |
| * indentation:4 | |
| * | |
| * created on: 2000may15 | |
| * created by: Steven \u24C7 Loomis | |
| * | |
| * This program packages the ICU data into different forms | |
| * (DLL, common data, etc.) | |
| */ | |
| // Defines _XOPEN_SOURCE for access to POSIX functions. | |
| // Must be before any other #includes. | |
| #include "uposixdefs.h" | |
| #include "unicode/utypes.h" | |
| #include "unicode/putil.h" | |
| #include "putilimp.h" | |
| #if U_HAVE_POPEN | |
| #if (U_PF_MINGW <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(__STRICT_ANSI__) | |
| /* popen/pclose aren't defined in strict ANSI on Cygwin and MinGW */ | |
| #undef __STRICT_ANSI__ | |
| #endif | |
| #endif | |
| #include "cmemory.h" | |
| #include "cstring.h" | |
| #include "filestrm.h" | |
| #include "toolutil.h" | |
| #include "unicode/uclean.h" | |
| #include "unewdata.h" | |
| #include "uoptions.h" | |
| #include "package.h" | |
| #include "pkg_icu.h" | |
| #include "pkg_genc.h" | |
| #include "pkg_gencmn.h" | |
| #include "flagparser.h" | |
| #include "filetools.h" | |
| #include "charstr.h" | |
| #include "uassert.h" | |
| #if U_HAVE_POPEN | |
| # include <unistd.h> | |
| #endif | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| U_CDECL_BEGIN | |
| #include "pkgtypes.h" | |
| U_CDECL_END | |
| #if U_HAVE_POPEN | |
| using icu::LocalPointerBase; | |
| U_DEFINE_LOCAL_OPEN_POINTER(LocalPipeFilePointer, FILE, pclose); | |
| #endif | |
| using icu::LocalMemory; | |
| static void loadLists(UPKGOptions *o, UErrorCode *status); | |
| static int32_t pkg_executeOptions(UPKGOptions *o); | |
| #ifdef WINDOWS_WITH_MSVC | |
| static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o); | |
| #endif | |
| static int32_t pkg_createSymLinks(const char *targetDir, UBool specialHandling=FALSE); | |
| static int32_t pkg_installLibrary(const char *installDir, const char *dir, UBool noVersion); | |
| static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName); | |
| static int32_t pkg_installCommonMode(const char *installDir, const char *fileName); | |
| #ifdef BUILD_DATA_WITHOUT_ASSEMBLY | |
| static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode); | |
| #endif | |
| #ifdef CAN_WRITE_OBJ_CODE | |
| static void pkg_createOptMatchArch(char *optMatchArch); | |
| static void pkg_destroyOptMatchArch(char *optMatchArch); | |
| #endif | |
| static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath); | |
| static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command = NULL, UBool specialHandling=FALSE); | |
| static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt); | |
| static void createFileNames(UPKGOptions *o, const char mode, const char *version_major, const char *version, const char *libName, const UBool reverseExt, UBool noVersion); | |
| static int32_t initializePkgDataFlags(UPKGOptions *o); | |
| static int32_t pkg_getPkgDataPath(UBool verbose, UOption *option); | |
| static int runCommand(const char* command, UBool specialHandling=FALSE); | |
| #define IN_COMMON_MODE(mode) (mode == 'a' || mode == 'c') | |
| #define IN_DLL_MODE(mode) (mode == 'd' || mode == 'l') | |
| #define IN_STATIC_MODE(mode) (mode == 's') | |
| #define IN_FILES_MODE(mode) (mode == 'f') | |
| enum { | |
| NAME, | |
| BLDOPT, | |
| MODE, | |
| HELP, | |
| HELP_QUESTION_MARK, | |
| VERBOSE, | |
| COPYRIGHT, | |
| COMMENT, | |
| DESTDIR, | |
| REBUILD, | |
| TEMPDIR, | |
| INSTALL, | |
| SOURCEDIR, | |
| ENTRYPOINT, | |
| REVISION, | |
| FORCE_PREFIX, | |
| LIBNAME, | |
| QUIET, | |
| WITHOUT_ASSEMBLY, | |
| PDS_BUILD, | |
| WIN_UWP_BUILD, | |
| WIN_DLL_ARCH, | |
| WIN_DYNAMICBASE | |
| }; | |
| /* This sets the modes that are available */ | |
| static struct { | |
| const char *name, *alt_name; | |
| const char *desc; | |
| } modes[] = { | |
| { "files", 0, "Uses raw data files (no effect). Installation copies all files to the target location." }, | |
| #if U_PLATFORM_HAS_WIN32_API | |
| { "dll", "library", "Generates one common data file and one shared library, <package>.dll"}, | |
| { "common", "archive", "Generates just the common file, <package>.dat"}, | |
| { "static", "static", "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX } | |
| #else | |
| #ifdef UDATA_SO_SUFFIX | |
| { "dll", "library", "Generates one shared library, <package>" UDATA_SO_SUFFIX }, | |
| #endif | |
| { "common", "archive", "Generates one common data file, <package>.dat" }, | |
| { "static", "static", "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX } | |
| #endif | |
| }; | |
| static UOption options[]={ | |
| /*00*/ UOPTION_DEF( "name", 'p', UOPT_REQUIRES_ARG), | |
| /*01*/ UOPTION_DEF( "bldopt", 'O', UOPT_REQUIRES_ARG), /* on Win32 it is release or debug */ | |
| /*02*/ UOPTION_DEF( "mode", 'm', UOPT_REQUIRES_ARG), | |
| /*03*/ UOPTION_HELP_H, /* -h */ | |
| /*04*/ UOPTION_HELP_QUESTION_MARK, /* -? */ | |
| /*05*/ UOPTION_VERBOSE, /* -v */ | |
| /*06*/ UOPTION_COPYRIGHT, /* -c */ | |
| /*07*/ UOPTION_DEF( "comment", 'C', UOPT_REQUIRES_ARG), | |
| /*08*/ UOPTION_DESTDIR, /* -d */ | |
| /*11*/ UOPTION_DEF( "rebuild", 'F', UOPT_NO_ARG), | |
| /*12*/ UOPTION_DEF( "tempdir", 'T', UOPT_REQUIRES_ARG), | |
| /*13*/ UOPTION_DEF( "install", 'I', UOPT_REQUIRES_ARG), | |
| /*14*/ UOPTION_SOURCEDIR , | |
| /*15*/ UOPTION_DEF( "entrypoint", 'e', UOPT_REQUIRES_ARG), | |
| /*16*/ UOPTION_DEF( "revision", 'r', UOPT_REQUIRES_ARG), | |
| /*17*/ UOPTION_DEF( "force-prefix", 'f', UOPT_NO_ARG), | |
| /*18*/ UOPTION_DEF( "libname", 'L', UOPT_REQUIRES_ARG), | |
| /*19*/ UOPTION_DEF( "quiet", 'q', UOPT_NO_ARG), | |
| /*20*/ UOPTION_DEF( "without-assembly", 'w', UOPT_NO_ARG), | |
| /*21*/ UOPTION_DEF("zos-pds-build", 'z', UOPT_NO_ARG), | |
| /*22*/ UOPTION_DEF("windows-uwp-build", 'u', UOPT_NO_ARG), | |
| /*23*/ UOPTION_DEF("windows-DLL-arch", 'a', UOPT_REQUIRES_ARG), | |
| /*24*/ UOPTION_DEF("windows-dynamicbase", 'b', UOPT_NO_ARG), | |
| }; | |
| /* This enum and the following char array should be kept in sync. */ | |
| enum { | |
| GENCCODE_ASSEMBLY_TYPE, | |
| SO_EXT, | |
| SOBJ_EXT, | |
| A_EXT, | |
| LIBPREFIX, | |
| LIB_EXT_ORDER, | |
| COMPILER, | |
| LIBFLAGS, | |
| GENLIB, | |
| LDICUDTFLAGS, | |
| LD_SONAME, | |
| RPATH_FLAGS, | |
| BIR_FLAGS, | |
| AR, | |
| ARFLAGS, | |
| RANLIB, | |
| INSTALL_CMD, | |
| PKGDATA_FLAGS_SIZE | |
| }; | |
| static const char* FLAG_NAMES[PKGDATA_FLAGS_SIZE] = { | |
| "GENCCODE_ASSEMBLY_TYPE", | |
| "SO", | |
| "SOBJ", | |
| "A", | |
| "LIBPREFIX", | |
| "LIB_EXT_ORDER", | |
| "COMPILE", | |
| "LIBFLAGS", | |
| "GENLIB", | |
| "LDICUDTFLAGS", | |
| "LD_SONAME", | |
| "RPATH_FLAGS", | |
| "BIR_LDFLAGS", | |
| "AR", | |
| "ARFLAGS", | |
| "RANLIB", | |
| "INSTALL_CMD" | |
| }; | |
| static char **pkgDataFlags = NULL; | |
| enum { | |
| LIB_FILE, | |
| LIB_FILE_VERSION_MAJOR, | |
| LIB_FILE_VERSION, | |
| LIB_FILE_VERSION_TMP, | |
| #if U_PLATFORM == U_PF_CYGWIN | |
| LIB_FILE_CYGWIN, | |
| LIB_FILE_CYGWIN_VERSION, | |
| #elif U_PLATFORM == U_PF_MINGW | |
| LIB_FILE_MINGW, | |
| #elif U_PLATFORM == U_PF_OS390 | |
| LIB_FILE_OS390BATCH_MAJOR, | |
| LIB_FILE_OS390BATCH_VERSION, | |
| #endif | |
| LIB_FILENAMES_SIZE | |
| }; | |
| static char libFileNames[LIB_FILENAMES_SIZE][256]; | |
| static UPKGOptions *pkg_checkFlag(UPKGOptions *o); | |
| const char options_help[][320]={ | |
| "Set the data name", | |
| #ifdef U_MAKE_IS_NMAKE | |
| "The directory where the ICU is located (e.g. <ICUROOT> which contains the bin directory)", | |
| #else | |
| "Specify options for the builder.", | |
| #endif | |
| "Specify the mode of building (see below; default: common)", | |
| "This usage text", | |
| "This usage text", | |
| "Make the output verbose", | |
| "Use the standard ICU copyright", | |
| "Use a custom comment (instead of the copyright)", | |
| "Specify the destination directory for files", | |
| "Force rebuilding of all data", | |
| "Specify temporary dir (default: output dir)", | |
| "Install the data (specify target)", | |
| "Specify a custom source directory", | |
| "Specify a custom entrypoint name (default: short name)", | |
| "Specify a version when packaging in dll or static mode", | |
| "Add package to all file names if not present", | |
| "Library name to build (if different than package name)", | |
| "Quiet mode. (e.g. Do not output a readme file for static libraries)", | |
| "Build the data without assembly code", | |
| "Build PDS dataset (zOS build only)", | |
| "Build for Universal Windows Platform (Windows build only)", | |
| "Specify the DLL machine architecture for LINK.exe (Windows build only)", | |
| "Ignored. Enable DYNAMICBASE on the DLL. This is now the default. (Windows build only)", | |
| }; | |
| const char *progname = "PKGDATA"; | |
| int | |
| main(int argc, char* argv[]) { | |
| int result = 0; | |
| /* FileStream *out; */ | |
| UPKGOptions o; | |
| CharList *tail; | |
| UBool needsHelp = FALSE; | |
| UErrorCode status = U_ZERO_ERROR; | |
| /* char tmp[1024]; */ | |
| uint32_t i; | |
| int32_t n; | |
| U_MAIN_INIT_ARGS(argc, argv); | |
| progname = argv[0]; | |
| options[MODE].value = "common"; | |
| /* read command line options */ | |
| argc=u_parseArgs(argc, argv, UPRV_LENGTHOF(options), options); | |
| /* error handling, printing usage message */ | |
| /* I've decided to simply print an error and quit. This tool has too | |
| many options to just display them all of the time. */ | |
| if(options[HELP].doesOccur || options[HELP_QUESTION_MARK].doesOccur) { | |
| needsHelp = TRUE; | |
| } | |
| else { | |
| if(!needsHelp && argc<0) { | |
| fprintf(stderr, | |
| "%s: error in command line argument \"%s\"\n", | |
| progname, | |
| argv[-argc]); | |
| fprintf(stderr, "Run '%s --help' for help.\n", progname); | |
| return 1; | |
| } | |
| #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) | |
| if(!options[BLDOPT].doesOccur && uprv_strcmp(options[MODE].value, "common") != 0) { | |
| if (pkg_getPkgDataPath(options[VERBOSE].doesOccur, &options[BLDOPT]) != 0) { | |
| fprintf(stderr, " required parameter is missing: -O is required for static and shared builds.\n"); | |
| fprintf(stderr, "Run '%s --help' for help.\n", progname); | |
| return 1; | |
| } | |
| } | |
| #else | |
| if(options[BLDOPT].doesOccur) { | |
| fprintf(stdout, "Warning: You are using the -O option which is not needed for MSVC build on Windows.\n"); | |
| } | |
| #endif | |
| if(!options[NAME].doesOccur) /* -O we already have - don't report it. */ | |
| { | |
| fprintf(stderr, " required parameter -p is missing \n"); | |
| fprintf(stderr, "Run '%s --help' for help.\n", progname); | |
| return 1; | |
| } | |
| if(argc == 1) { | |
| fprintf(stderr, | |
| "No input files specified.\n" | |
| "Run '%s --help' for help.\n", progname); | |
| return 1; | |
| } | |
| } /* end !needsHelp */ | |
| if(argc<0 || needsHelp ) { | |
| fprintf(stderr, | |
| "usage: %s [-options] [-] [packageFile] \n" | |
| "\tProduce packaged ICU data from the given list(s) of files.\n" | |
| "\t'-' by itself means to read from stdin.\n" | |
| "\tpackageFile is a text file containing the list of files to package.\n", | |
| progname); | |
| fprintf(stderr, "\n options:\n"); | |
| for(i=0;i<UPRV_LENGTHOF(options);i++) { | |
| fprintf(stderr, "%-5s -%c %s%-10s %s\n", | |
| (i<1?"[REQ]":""), | |
| options[i].shortName, | |
| options[i].longName ? "or --" : " ", | |
| options[i].longName ? options[i].longName : "", | |
| options_help[i]); | |
| } | |
| fprintf(stderr, "modes: (-m option)\n"); | |
| for(i=0;i<UPRV_LENGTHOF(modes);i++) { | |
| fprintf(stderr, " %-9s ", modes[i].name); | |
| if (modes[i].alt_name) { | |
| fprintf(stderr, "/ %-9s", modes[i].alt_name); | |
| } else { | |
| fprintf(stderr, " "); | |
| } | |
| fprintf(stderr, " %s\n", modes[i].desc); | |
| } | |
| return 1; | |
| } | |
| /* OK, fill in the options struct */ | |
| uprv_memset(&o, 0, sizeof(o)); | |
| o.mode = options[MODE].value; | |
| o.version = options[REVISION].doesOccur ? options[REVISION].value : 0; | |
| o.shortName = options[NAME].value; | |
| { | |
| int32_t len = (int32_t)uprv_strlen(o.shortName); | |
| char *csname, *cp; | |
| const char *sp; | |
| cp = csname = (char *) uprv_malloc((len + 1 + 1) * sizeof(*o.cShortName)); | |
| if (*(sp = o.shortName)) { | |
| *cp++ = isalpha(*sp) ? * sp : '_'; | |
| for (++sp; *sp; ++sp) { | |
| *cp++ = isalnum(*sp) ? *sp : '_'; | |
| } | |
| } | |
| *cp = 0; | |
| o.cShortName = csname; | |
| } | |
| if(options[LIBNAME].doesOccur) { /* get libname from shortname, or explicit -L parameter */ | |
| o.libName = options[LIBNAME].value; | |
| } else { | |
| o.libName = o.shortName; | |
| } | |
| if(options[QUIET].doesOccur) { | |
| o.quiet = TRUE; | |
| } else { | |
| o.quiet = FALSE; | |
| } | |
| if(options[PDS_BUILD].doesOccur) { | |
| #if U_PLATFORM == U_PF_OS390 | |
| o.pdsbuild = TRUE; | |
| #else | |
| o.pdsbuild = FALSE; | |
| fprintf(stdout, "Warning: You are using the -z option which only works on z/OS.\n"); | |
| #endif | |
| } else { | |
| o.pdsbuild = FALSE; | |
| } | |
| o.verbose = options[VERBOSE].doesOccur; | |
| #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) /* on UNIX, we'll just include the file... */ | |
| if (options[BLDOPT].doesOccur) { | |
| o.options = options[BLDOPT].value; | |
| } else { | |
| o.options = NULL; | |
| } | |
| #endif | |
| if(options[COPYRIGHT].doesOccur) { | |
| o.comment = U_COPYRIGHT_STRING; | |
| } else if (options[COMMENT].doesOccur) { | |
| o.comment = options[COMMENT].value; | |
| } | |
| if( options[DESTDIR].doesOccur ) { | |
| o.targetDir = options[DESTDIR].value; | |
| } else { | |
| o.targetDir = "."; /* cwd */ | |
| } | |
| o.rebuild = options[REBUILD].doesOccur; | |
| if( options[TEMPDIR].doesOccur ) { | |
| o.tmpDir = options[TEMPDIR].value; | |
| } else { | |
| o.tmpDir = o.targetDir; | |
| } | |
| if( options[INSTALL].doesOccur ) { | |
| o.install = options[INSTALL].value; | |
| } else { | |
| o.install = NULL; | |
| } | |
| if( options[SOURCEDIR].doesOccur ) { | |
| o.srcDir = options[SOURCEDIR].value; | |
| } else { | |
| o.srcDir = "."; | |
| } | |
| if( options[ENTRYPOINT].doesOccur ) { | |
| o.entryName = options[ENTRYPOINT].value; | |
| } else { | |
| o.entryName = o.cShortName; | |
| } | |
| o.withoutAssembly = FALSE; | |
| if (options[WITHOUT_ASSEMBLY].doesOccur) { | |
| #ifndef BUILD_DATA_WITHOUT_ASSEMBLY | |
| fprintf(stdout, "Warning: You are using the option to build without assembly code which is not supported on this platform.\n"); | |
| fprintf(stdout, "Warning: This option will be ignored.\n"); | |
| #else | |
| o.withoutAssembly = TRUE; | |
| #endif | |
| } | |
| if (options[WIN_DYNAMICBASE].doesOccur) { | |
| fprintf(stdout, "Note: Ignoring option -b (windows-dynamicbase).\n"); | |
| } | |
| /* OK options are set up. Now the file lists. */ | |
| tail = NULL; | |
| for( n=1; n<argc; n++) { | |
| o.fileListFiles = pkg_appendToList(o.fileListFiles, &tail, uprv_strdup(argv[n])); | |
| } | |
| /* load the files */ | |
| loadLists(&o, &status); | |
| if( U_FAILURE(status) ) { | |
| fprintf(stderr, "error loading input file lists: %s\n", u_errorName(status)); | |
| return 2; | |
| } | |
| result = pkg_executeOptions(&o); | |
| if (pkgDataFlags != NULL) { | |
| for (n = 0; n < PKGDATA_FLAGS_SIZE; n++) { | |
| if (pkgDataFlags[n] != NULL) { | |
| uprv_free(pkgDataFlags[n]); | |
| } | |
| } | |
| uprv_free(pkgDataFlags); | |
| } | |
| if (o.cShortName != NULL) { | |
| uprv_free((char *)o.cShortName); | |
| } | |
| if (o.fileListFiles != NULL) { | |
| pkg_deleteList(o.fileListFiles); | |
| } | |
| if (o.filePaths != NULL) { | |
| pkg_deleteList(o.filePaths); | |
| } | |
| if (o.files != NULL) { | |
| pkg_deleteList(o.files); | |
| } | |
| return result; | |
| } | |
| static int runCommand(const char* command, UBool specialHandling) { | |
| char *cmd = NULL; | |
| char cmdBuffer[SMALL_BUFFER_MAX_SIZE]; | |
| int32_t len = static_cast<int32_t>(strlen(command)); | |
| if (len == 0) { | |
| return 0; | |
| } | |
| if (!specialHandling) { | |
| #if defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW || U_PLATFORM == U_PF_OS400 | |
| if ((len + BUFFER_PADDING_SIZE) >= SMALL_BUFFER_MAX_SIZE) { | |
| cmd = (char *)uprv_malloc(len + BUFFER_PADDING_SIZE); | |
| } else { | |
| cmd = cmdBuffer; | |
| } | |
| #if defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW | |
| sprintf(cmd, "bash -c \"%s\"", command); | |
| #elif U_PLATFORM == U_PF_OS400 | |
| sprintf(cmd, "QSH CMD('%s')", command); | |
| #endif | |
| #else | |
| goto normal_command_mode; | |
| #endif | |
| } else { | |
| #if !(defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW || U_PLATFORM == U_PF_OS400) | |
| normal_command_mode: | |
| #endif | |
| cmd = (char *)command; | |
| } | |
| printf("pkgdata: %s\n", cmd); | |
| int result = system(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "-- return status = %d\n", result); | |
| result = 1; // system() result code is platform specific. | |
| } | |
| if (cmd != cmdBuffer && cmd != command) { | |
| uprv_free(cmd); | |
| } | |
| return result; | |
| } | |
| #define LN_CMD "ln -s" | |
| #define RM_CMD "rm -f" | |
| static int32_t pkg_executeOptions(UPKGOptions *o) { | |
| int32_t result = 0; | |
| const char mode = o->mode[0]; | |
| char targetDir[SMALL_BUFFER_MAX_SIZE] = ""; | |
| char tmpDir[SMALL_BUFFER_MAX_SIZE] = ""; | |
| char datFileName[SMALL_BUFFER_MAX_SIZE] = ""; | |
| char datFileNamePath[LARGE_BUFFER_MAX_SIZE] = ""; | |
| char checkLibFile[LARGE_BUFFER_MAX_SIZE] = ""; | |
| initializePkgDataFlags(o); | |
| if (IN_FILES_MODE(mode)) { | |
| /* Copy the raw data to the installation directory. */ | |
| if (o->install != NULL) { | |
| uprv_strcpy(targetDir, o->install); | |
| if (o->shortName != NULL) { | |
| uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING); | |
| uprv_strcat(targetDir, o->shortName); | |
| } | |
| if(o->verbose) { | |
| fprintf(stdout, "# Install: Files mode, copying files to %s..\n", targetDir); | |
| } | |
| result = pkg_installFileMode(targetDir, o->srcDir, o->fileListFiles->str); | |
| } | |
| return result; | |
| } else /* if (IN_COMMON_MODE(mode) || IN_DLL_MODE(mode) || IN_STATIC_MODE(mode)) */ { | |
| UBool noVersion = FALSE; | |
| uprv_strcpy(targetDir, o->targetDir); | |
| uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING); | |
| uprv_strcpy(tmpDir, o->tmpDir); | |
| uprv_strcat(tmpDir, PKGDATA_FILE_SEP_STRING); | |
| uprv_strcpy(datFileNamePath, tmpDir); | |
| uprv_strcpy(datFileName, o->shortName); | |
| uprv_strcat(datFileName, UDATA_CMN_SUFFIX); | |
| uprv_strcat(datFileNamePath, datFileName); | |
| if(o->verbose) { | |
| fprintf(stdout, "# Writing package file %s ..\n", datFileNamePath); | |
| } | |
| result = writePackageDatFile(datFileNamePath, o->comment, o->srcDir, o->fileListFiles->str, NULL, U_CHARSET_FAMILY ? 'e' : U_IS_BIG_ENDIAN ? 'b' : 'l'); | |
| if (result != 0) { | |
| fprintf(stderr,"Error writing package dat file.\n"); | |
| return result; | |
| } | |
| if (IN_COMMON_MODE(mode)) { | |
| char targetFileNamePath[LARGE_BUFFER_MAX_SIZE] = ""; | |
| uprv_strcpy(targetFileNamePath, targetDir); | |
| uprv_strcat(targetFileNamePath, datFileName); | |
| /* Move the dat file created to the target directory. */ | |
| if (uprv_strcmp(datFileNamePath, targetFileNamePath) != 0) { | |
| if (T_FileStream_file_exists(targetFileNamePath)) { | |
| if ((result = remove(targetFileNamePath)) != 0) { | |
| fprintf(stderr, "Unable to remove old dat file: %s\n", | |
| targetFileNamePath); | |
| return result; | |
| } | |
| } | |
| result = rename(datFileNamePath, targetFileNamePath); | |
| if (o->verbose) { | |
| fprintf(stdout, "# Moving package file to %s ..\n", | |
| targetFileNamePath); | |
| } | |
| if (result != 0) { | |
| fprintf( | |
| stderr, | |
| "Unable to move dat file (%s) to target location (%s).\n", | |
| datFileNamePath, targetFileNamePath); | |
| return result; | |
| } | |
| } | |
| if (o->install != NULL) { | |
| result = pkg_installCommonMode(o->install, targetFileNamePath); | |
| } | |
| return result; | |
| } else /* if (IN_STATIC_MODE(mode) || IN_DLL_MODE(mode)) */ { | |
| char gencFilePath[SMALL_BUFFER_MAX_SIZE] = ""; | |
| char version_major[10] = ""; | |
| UBool reverseExt = FALSE; | |
| #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) | |
| /* Get the version major number. */ | |
| if (o->version != NULL) { | |
| for (uint32_t i = 0;i < sizeof(version_major);i++) { | |
| if (o->version[i] == '.') { | |
| version_major[i] = 0; | |
| break; | |
| } | |
| version_major[i] = o->version[i]; | |
| } | |
| } else { | |
| noVersion = TRUE; | |
| if (IN_DLL_MODE(mode)) { | |
| fprintf(stdout, "Warning: Providing a revision number with the -r option is recommended when packaging data in the current mode.\n"); | |
| } | |
| } | |
| #if U_PLATFORM != U_PF_OS400 | |
| /* Certain platforms have different library extension ordering. (e.g. libicudata.##.so vs libicudata.so.##) | |
| * reverseExt is FALSE if the suffix should be the version number. | |
| */ | |
| if (pkgDataFlags[LIB_EXT_ORDER][uprv_strlen(pkgDataFlags[LIB_EXT_ORDER])-1] == pkgDataFlags[SO_EXT][uprv_strlen(pkgDataFlags[SO_EXT])-1]) { | |
| reverseExt = TRUE; | |
| } | |
| #endif | |
| /* Using the base libName and version number, generate the library file names. */ | |
| createFileNames(o, mode, version_major, o->version == NULL ? "" : o->version, o->libName, reverseExt, noVersion); | |
| if ((o->version!=NULL || IN_STATIC_MODE(mode)) && o->rebuild == FALSE && o->pdsbuild == FALSE) { | |
| /* Check to see if a previous built data library file exists and check if it is the latest. */ | |
| sprintf(checkLibFile, "%s%s", targetDir, libFileNames[LIB_FILE_VERSION]); | |
| if (T_FileStream_file_exists(checkLibFile)) { | |
| if (isFileModTimeLater(checkLibFile, o->srcDir, TRUE) && isFileModTimeLater(checkLibFile, o->options)) { | |
| if (o->install != NULL) { | |
| if(o->verbose) { | |
| fprintf(stdout, "# Installing already-built library into %s\n", o->install); | |
| } | |
| result = pkg_installLibrary(o->install, targetDir, noVersion); | |
| } else { | |
| if(o->verbose) { | |
| printf("# Not rebuilding %s - up to date.\n", checkLibFile); | |
| } | |
| } | |
| return result; | |
| } else if (o->verbose && (o->install!=NULL)) { | |
| fprintf(stdout, "# Not installing up-to-date library %s into %s\n", checkLibFile, o->install); | |
| } | |
| } else if(o->verbose && (o->install!=NULL)) { | |
| fprintf(stdout, "# Not installing missing %s into %s\n", checkLibFile, o->install); | |
| } | |
| } | |
| if (pkg_checkFlag(o) == NULL) { | |
| /* Error occurred. */ | |
| return result; | |
| } | |
| #endif | |
| if (!o->withoutAssembly && pkgDataFlags[GENCCODE_ASSEMBLY_TYPE][0] != 0) { | |
| const char* genccodeAssembly = pkgDataFlags[GENCCODE_ASSEMBLY_TYPE]; | |
| if(o->verbose) { | |
| fprintf(stdout, "# Generating assembly code %s of type %s ..\n", gencFilePath, genccodeAssembly); | |
| } | |
| /* Offset genccodeAssembly by 3 because "-a " */ | |
| if (genccodeAssembly && | |
| (uprv_strlen(genccodeAssembly)>3) && | |
| checkAssemblyHeaderName(genccodeAssembly+3)) { | |
| writeAssemblyCode( | |
| datFileNamePath, | |
| o->tmpDir, | |
| o->entryName, | |
| NULL, | |
| gencFilePath, | |
| sizeof(gencFilePath)); | |
| result = pkg_createWithAssemblyCode(targetDir, mode, gencFilePath); | |
| if (result != 0) { | |
| fprintf(stderr, "Error generating assembly code for data.\n"); | |
| return result; | |
| } else if (IN_STATIC_MODE(mode)) { | |
| if(o->install != NULL) { | |
| if(o->verbose) { | |
| fprintf(stdout, "# Installing static library into %s\n", o->install); | |
| } | |
| result = pkg_installLibrary(o->install, targetDir, noVersion); | |
| } | |
| return result; | |
| } | |
| } else { | |
| fprintf(stderr,"Assembly type \"%s\" is unknown.\n", genccodeAssembly); | |
| return -1; | |
| } | |
| } else { | |
| if(o->verbose) { | |
| fprintf(stdout, "# Writing object code to %s ..\n", gencFilePath); | |
| } | |
| if (o->withoutAssembly) { | |
| #ifdef BUILD_DATA_WITHOUT_ASSEMBLY | |
| result = pkg_createWithoutAssemblyCode(o, targetDir, mode); | |
| #else | |
| /* This error should not occur. */ | |
| fprintf(stderr, "Error- BUILD_DATA_WITHOUT_ASSEMBLY is not defined. Internal error.\n"); | |
| #endif | |
| } else { | |
| #ifdef CAN_WRITE_OBJ_CODE | |
| /* Try to detect the arch type, use NULL if unsuccessful */ | |
| char optMatchArch[10] = { 0 }; | |
| pkg_createOptMatchArch(optMatchArch); | |
| writeObjectCode( | |
| datFileNamePath, | |
| o->tmpDir, | |
| o->entryName, | |
| (optMatchArch[0] == 0 ? NULL : optMatchArch), | |
| NULL, | |
| gencFilePath, | |
| sizeof(gencFilePath), | |
| TRUE); | |
| pkg_destroyOptMatchArch(optMatchArch); | |
| #if U_PLATFORM_IS_LINUX_BASED | |
| result = pkg_generateLibraryFile(targetDir, mode, gencFilePath); | |
| #elif defined(WINDOWS_WITH_MSVC) | |
| result = pkg_createWindowsDLL(mode, gencFilePath, o); | |
| #endif | |
| #elif defined(BUILD_DATA_WITHOUT_ASSEMBLY) | |
| result = pkg_createWithoutAssemblyCode(o, targetDir, mode); | |
| #else | |
| fprintf(stderr, "Error- neither CAN_WRITE_OBJ_CODE nor BUILD_DATA_WITHOUT_ASSEMBLY are defined. Internal error.\n"); | |
| return 1; | |
| #endif | |
| } | |
| if (result != 0) { | |
| fprintf(stderr, "Error generating package data.\n"); | |
| return result; | |
| } | |
| } | |
| #if !U_PLATFORM_USES_ONLY_WIN32_API | |
| if(!IN_STATIC_MODE(mode)) { | |
| /* Certain platforms uses archive library. (e.g. AIX) */ | |
| if(o->verbose) { | |
| fprintf(stdout, "# Creating data archive library file ..\n"); | |
| } | |
| result = pkg_archiveLibrary(targetDir, o->version, reverseExt); | |
| if (result != 0) { | |
| fprintf(stderr, "Error creating data archive library file.\n"); | |
| return result; | |
| } | |
| #if U_PLATFORM != U_PF_OS400 | |
| if (!noVersion) { | |
| /* Create symbolic links for the final library file. */ | |
| #if U_PLATFORM == U_PF_OS390 | |
| result = pkg_createSymLinks(targetDir, o->pdsbuild); | |
| #else | |
| result = pkg_createSymLinks(targetDir, noVersion); | |
| #endif | |
| if (result != 0) { | |
| fprintf(stderr, "Error creating symbolic links of the data library file.\n"); | |
| return result; | |
| } | |
| } | |
| #endif | |
| } /* !IN_STATIC_MODE */ | |
| #endif | |
| #if !U_PLATFORM_USES_ONLY_WIN32_API | |
| /* Install the libraries if option was set. */ | |
| if (o->install != NULL) { | |
| if(o->verbose) { | |
| fprintf(stdout, "# Installing library file to %s ..\n", o->install); | |
| } | |
| result = pkg_installLibrary(o->install, targetDir, noVersion); | |
| if (result != 0) { | |
| fprintf(stderr, "Error installing the data library.\n"); | |
| return result; | |
| } | |
| } | |
| #endif | |
| } | |
| } | |
| return result; | |
| } | |
| /* Initialize the pkgDataFlags with the option file given. */ | |
| static int32_t initializePkgDataFlags(UPKGOptions *o) { | |
| UErrorCode status = U_ZERO_ERROR; | |
| int32_t result = 0; | |
| int32_t currentBufferSize = SMALL_BUFFER_MAX_SIZE; | |
| int32_t tmpResult = 0; | |
| /* Initialize pkgdataFlags */ | |
| pkgDataFlags = (char**)uprv_malloc(sizeof(char*) * PKGDATA_FLAGS_SIZE); | |
| /* If we run out of space, allocate more */ | |
| #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) | |
| do { | |
| #endif | |
| if (pkgDataFlags != NULL) { | |
| for (int32_t i = 0; i < PKGDATA_FLAGS_SIZE; i++) { | |
| pkgDataFlags[i] = (char*)uprv_malloc(sizeof(char) * currentBufferSize); | |
| if (pkgDataFlags[i] != NULL) { | |
| pkgDataFlags[i][0] = 0; | |
| } else { | |
| fprintf(stderr,"Error allocating memory for pkgDataFlags.\n"); | |
| /* If an error occurs, ensure that the rest of the array is NULL */ | |
| for (int32_t n = i + 1; n < PKGDATA_FLAGS_SIZE; n++) { | |
| pkgDataFlags[n] = NULL; | |
| } | |
| return -1; | |
| } | |
| } | |
| } else { | |
| fprintf(stderr,"Error allocating memory for pkgDataFlags.\n"); | |
| return -1; | |
| } | |
| if (o->options == NULL) { | |
| return result; | |
| } | |
| #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) | |
| /* Read in options file. */ | |
| if(o->verbose) { | |
| fprintf(stdout, "# Reading options file %s\n", o->options); | |
| } | |
| status = U_ZERO_ERROR; | |
| tmpResult = parseFlagsFile(o->options, pkgDataFlags, currentBufferSize, FLAG_NAMES, (int32_t)PKGDATA_FLAGS_SIZE, &status); | |
| if (status == U_BUFFER_OVERFLOW_ERROR) { | |
| for (int32_t i = 0; i < PKGDATA_FLAGS_SIZE; i++) { | |
| if (pkgDataFlags[i]) { | |
| uprv_free(pkgDataFlags[i]); | |
| pkgDataFlags[i] = NULL; | |
| } | |
| } | |
| currentBufferSize = tmpResult; | |
| } else if (U_FAILURE(status)) { | |
| fprintf(stderr,"Unable to open or read \"%s\" option file. status = %s\n", o->options, u_errorName(status)); | |
| return -1; | |
| } | |
| #endif | |
| if(o->verbose) { | |
| fprintf(stdout, "# pkgDataFlags=\n"); | |
| for(int32_t i=0;i<PKGDATA_FLAGS_SIZE;i++) { | |
| fprintf(stdout, " [%d] %s: %s\n", i, FLAG_NAMES[i], pkgDataFlags[i]); | |
| } | |
| fprintf(stdout, "\n"); | |
| } | |
| #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) | |
| } while (status == U_BUFFER_OVERFLOW_ERROR); | |
| #endif | |
| return result; | |
| } | |
| /* | |
| * Given the base libName and version numbers, generate the libary file names and store it in libFileNames. | |
| * Depending on the configuration, the library name may either end with version number or shared object suffix. | |
| */ | |
| static void createFileNames(UPKGOptions *o, const char mode, const char *version_major, const char *version, const char *libName, UBool reverseExt, UBool noVersion) { | |
| const char* FILE_EXTENSION_SEP = uprv_strlen(pkgDataFlags[SO_EXT]) == 0 ? "" : "."; | |
| const char* FILE_SUFFIX = pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : ""; | |
| #if U_PLATFORM == U_PF_MINGW | |
| /* MinGW does not need the library prefix when building in dll mode. */ | |
| if (IN_DLL_MODE(mode)) { | |
| sprintf(libFileNames[LIB_FILE], "%s", libName); | |
| } else { | |
| sprintf(libFileNames[LIB_FILE], "%s%s%s", | |
| (strstr(libName, "icudt") ? "lib" : ""), | |
| pkgDataFlags[LIBPREFIX], | |
| libName); | |
| } | |
| #else | |
| sprintf(libFileNames[LIB_FILE], "%s%s", | |
| pkgDataFlags[LIBPREFIX], | |
| libName); | |
| #endif | |
| if(o->verbose) { | |
| fprintf(stdout, "# libFileName[LIB_FILE] = %s\n", libFileNames[LIB_FILE]); | |
| } | |
| #if U_PLATFORM == U_PF_MINGW | |
| // Name the import library lib*.dll.a | |
| sprintf(libFileNames[LIB_FILE_MINGW], "lib%s.dll.a", libName); | |
| #elif U_PLATFORM == U_PF_CYGWIN | |
| sprintf(libFileNames[LIB_FILE_CYGWIN], "cyg%s%s%s", | |
| libName, | |
| FILE_EXTENSION_SEP, | |
| pkgDataFlags[SO_EXT]); | |
| sprintf(libFileNames[LIB_FILE_CYGWIN_VERSION], "cyg%s%s%s%s", | |
| libName, | |
| version_major, | |
| FILE_EXTENSION_SEP, | |
| pkgDataFlags[SO_EXT]); | |
| uprv_strcat(pkgDataFlags[SO_EXT], "."); | |
| uprv_strcat(pkgDataFlags[SO_EXT], pkgDataFlags[A_EXT]); | |
| #elif U_PLATFORM == U_PF_OS400 || defined(_AIX) | |
| sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s", | |
| libFileNames[LIB_FILE], | |
| FILE_EXTENSION_SEP, | |
| pkgDataFlags[SOBJ_EXT]); | |
| #elif U_PLATFORM == U_PF_OS390 | |
| sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s%s%s", | |
| libFileNames[LIB_FILE], | |
| pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "", | |
| reverseExt ? version : pkgDataFlags[SOBJ_EXT], | |
| FILE_EXTENSION_SEP, | |
| reverseExt ? pkgDataFlags[SOBJ_EXT] : version); | |
| sprintf(libFileNames[LIB_FILE_OS390BATCH_VERSION], "%s%s.x", | |
| libFileNames[LIB_FILE], | |
| version); | |
| sprintf(libFileNames[LIB_FILE_OS390BATCH_MAJOR], "%s%s.x", | |
| libFileNames[LIB_FILE], | |
| version_major); | |
| #else | |
| if (noVersion && !reverseExt) { | |
| sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s", | |
| libFileNames[LIB_FILE], | |
| FILE_SUFFIX, | |
| pkgDataFlags[SOBJ_EXT]); | |
| } else { | |
| sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s%s%s", | |
| libFileNames[LIB_FILE], | |
| FILE_SUFFIX, | |
| reverseExt ? version : pkgDataFlags[SOBJ_EXT], | |
| FILE_EXTENSION_SEP, | |
| reverseExt ? pkgDataFlags[SOBJ_EXT] : version); | |
| } | |
| #endif | |
| if (noVersion && !reverseExt) { | |
| sprintf(libFileNames[LIB_FILE_VERSION_MAJOR], "%s%s%s", | |
| libFileNames[LIB_FILE], | |
| FILE_SUFFIX, | |
| pkgDataFlags[SO_EXT]); | |
| sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s", | |
| libFileNames[LIB_FILE], | |
| FILE_SUFFIX, | |
| pkgDataFlags[SO_EXT]); | |
| } else { | |
| sprintf(libFileNames[LIB_FILE_VERSION_MAJOR], "%s%s%s%s%s", | |
| libFileNames[LIB_FILE], | |
| FILE_SUFFIX, | |
| reverseExt ? version_major : pkgDataFlags[SO_EXT], | |
| FILE_EXTENSION_SEP, | |
| reverseExt ? pkgDataFlags[SO_EXT] : version_major); | |
| sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s%s%s", | |
| libFileNames[LIB_FILE], | |
| FILE_SUFFIX, | |
| reverseExt ? version : pkgDataFlags[SO_EXT], | |
| FILE_EXTENSION_SEP, | |
| reverseExt ? pkgDataFlags[SO_EXT] : version); | |
| } | |
| if(o->verbose) { | |
| fprintf(stdout, "# libFileName[LIB_FILE_VERSION] = %s\n", libFileNames[LIB_FILE_VERSION]); | |
| } | |
| #if U_PF_MINGW <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN | |
| /* Cygwin and MinGW only deals with the version major number. */ | |
| uprv_strcpy(libFileNames[LIB_FILE_VERSION_TMP], libFileNames[LIB_FILE_VERSION_MAJOR]); | |
| #endif | |
| if(IN_STATIC_MODE(mode)) { | |
| sprintf(libFileNames[LIB_FILE_VERSION], "%s.%s", libFileNames[LIB_FILE], pkgDataFlags[A_EXT]); | |
| libFileNames[LIB_FILE_VERSION_MAJOR][0]=0; | |
| if(o->verbose) { | |
| fprintf(stdout, "# libFileName[LIB_FILE_VERSION] = %s (static)\n", libFileNames[LIB_FILE_VERSION]); | |
| } | |
| } | |
| } | |
| /* Create the symbolic links for the final library file. */ | |
| static int32_t pkg_createSymLinks(const char *targetDir, UBool specialHandling) { | |
| int32_t result = 0; | |
| char cmd[LARGE_BUFFER_MAX_SIZE]; | |
| char name1[SMALL_BUFFER_MAX_SIZE]; /* symlink file name */ | |
| char name2[SMALL_BUFFER_MAX_SIZE]; /* file name to symlink */ | |
| const char* FILE_EXTENSION_SEP = uprv_strlen(pkgDataFlags[SO_EXT]) == 0 ? "" : "."; | |
| #if U_PLATFORM != U_PF_CYGWIN | |
| /* No symbolic link to make. */ | |
| if (uprv_strlen(libFileNames[LIB_FILE_VERSION]) == 0 || uprv_strlen(libFileNames[LIB_FILE_VERSION_MAJOR]) == 0 || | |
| uprv_strcmp(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_MAJOR]) == 0) { | |
| return result; | |
| } | |
| sprintf(cmd, "cd %s && %s %s && %s %s %s", | |
| targetDir, | |
| RM_CMD, | |
| libFileNames[LIB_FILE_VERSION_MAJOR], | |
| LN_CMD, | |
| libFileNames[LIB_FILE_VERSION], | |
| libFileNames[LIB_FILE_VERSION_MAJOR]); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Error creating symbolic links. Failed command: %s\n", cmd); | |
| return result; | |
| } | |
| #endif | |
| if (specialHandling) { | |
| #if U_PLATFORM == U_PF_CYGWIN | |
| sprintf(name1, "%s", libFileNames[LIB_FILE_CYGWIN]); | |
| sprintf(name2, "%s", libFileNames[LIB_FILE_CYGWIN_VERSION]); | |
| #elif U_PLATFORM == U_PF_OS390 | |
| /* Create the symbolic links for the import data */ | |
| /* Use the cmd buffer to store path to import data file to check its existence */ | |
| sprintf(cmd, "%s/%s", targetDir, libFileNames[LIB_FILE_OS390BATCH_VERSION]); | |
| if (T_FileStream_file_exists(cmd)) { | |
| sprintf(cmd, "cd %s && %s %s && %s %s %s", | |
| targetDir, | |
| RM_CMD, | |
| libFileNames[LIB_FILE_OS390BATCH_MAJOR], | |
| LN_CMD, | |
| libFileNames[LIB_FILE_OS390BATCH_VERSION], | |
| libFileNames[LIB_FILE_OS390BATCH_MAJOR]); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Error creating symbolic links. Failed command: %s\n", cmd); | |
| return result; | |
| } | |
| sprintf(cmd, "cd %s && %s %s.x && %s %s %s.x", | |
| targetDir, | |
| RM_CMD, | |
| libFileNames[LIB_FILE], | |
| LN_CMD, | |
| libFileNames[LIB_FILE_OS390BATCH_VERSION], | |
| libFileNames[LIB_FILE]); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Error creating symbolic links. Failed command: %s\n", cmd); | |
| return result; | |
| } | |
| } | |
| /* Needs to be set here because special handling skips it */ | |
| sprintf(name1, "%s%s%s", libFileNames[LIB_FILE], FILE_EXTENSION_SEP, pkgDataFlags[SO_EXT]); | |
| sprintf(name2, "%s", libFileNames[LIB_FILE_VERSION]); | |
| #else | |
| goto normal_symlink_mode; | |
| #endif | |
| } else { | |
| #if U_PLATFORM != U_PF_CYGWIN | |
| normal_symlink_mode: | |
| #endif | |
| sprintf(name1, "%s%s%s", libFileNames[LIB_FILE], FILE_EXTENSION_SEP, pkgDataFlags[SO_EXT]); | |
| sprintf(name2, "%s", libFileNames[LIB_FILE_VERSION]); | |
| } | |
| sprintf(cmd, "cd %s && %s %s && %s %s %s", | |
| targetDir, | |
| RM_CMD, | |
| name1, | |
| LN_CMD, | |
| name2, | |
| name1); | |
| result = runCommand(cmd); | |
| return result; | |
| } | |
| static int32_t pkg_installLibrary(const char *installDir, const char *targetDir, UBool noVersion) { | |
| int32_t result = 0; | |
| char cmd[SMALL_BUFFER_MAX_SIZE]; | |
| auto ret = snprintf(cmd, | |
| SMALL_BUFFER_MAX_SIZE, | |
| "cd %s && %s %s %s%s%s", | |
| targetDir, | |
| pkgDataFlags[INSTALL_CMD], | |
| libFileNames[LIB_FILE_VERSION], | |
| installDir, PKGDATA_FILE_SEP_STRING, libFileNames[LIB_FILE_VERSION]); | |
| (void)ret; | |
| U_ASSERT(0 <= ret && ret < SMALL_BUFFER_MAX_SIZE); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Error installing library. Failed command: %s\n", cmd); | |
| return result; | |
| } | |
| #ifdef CYGWINMSVC | |
| sprintf(cmd, "cd %s && %s %s.lib %s", | |
| targetDir, | |
| pkgDataFlags[INSTALL_CMD], | |
| libFileNames[LIB_FILE], | |
| installDir | |
| ); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Error installing library. Failed command: %s\n", cmd); | |
| return result; | |
| } | |
| #elif U_PLATFORM == U_PF_CYGWIN | |
| sprintf(cmd, "cd %s && %s %s %s", | |
| targetDir, | |
| pkgDataFlags[INSTALL_CMD], | |
| libFileNames[LIB_FILE_CYGWIN_VERSION], | |
| installDir | |
| ); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Error installing library. Failed command: %s\n", cmd); | |
| return result; | |
| } | |
| #elif U_PLATFORM == U_PF_OS390 | |
| if (T_FileStream_file_exists(libFileNames[LIB_FILE_OS390BATCH_VERSION])) { | |
| sprintf(cmd, "%s %s %s", | |
| pkgDataFlags[INSTALL_CMD], | |
| libFileNames[LIB_FILE_OS390BATCH_VERSION], | |
| installDir | |
| ); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Error installing library. Failed command: %s\n", cmd); | |
| return result; | |
| } | |
| } | |
| #endif | |
| if (noVersion) { | |
| return result; | |
| } else { | |
| return pkg_createSymLinks(installDir, TRUE); | |
| } | |
| } | |
| static int32_t pkg_installCommonMode(const char *installDir, const char *fileName) { | |
| int32_t result = 0; | |
| char cmd[SMALL_BUFFER_MAX_SIZE] = ""; | |
| if (!T_FileStream_file_exists(installDir)) { | |
| UErrorCode status = U_ZERO_ERROR; | |
| uprv_mkdir(installDir, &status); | |
| if (U_FAILURE(status)) { | |
| fprintf(stderr, "Error creating installation directory: %s\n", installDir); | |
| return -1; | |
| } | |
| } | |
| #ifndef U_WINDOWS_WITH_MSVC | |
| sprintf(cmd, "%s %s %s", pkgDataFlags[INSTALL_CMD], fileName, installDir); | |
| #else | |
| sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, fileName, installDir, WIN_INSTALL_CMD_FLAGS); | |
| #endif | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Failed to install data file with command: %s\n", cmd); | |
| } | |
| return result; | |
| } | |
| #ifdef U_WINDOWS_MSVC | |
| /* Copy commands for installing the raw data files on Windows. */ | |
| #define WIN_INSTALL_CMD "xcopy" | |
| #define WIN_INSTALL_CMD_FLAGS "/E /Y /K" | |
| #endif | |
| static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName) { | |
| int32_t result = 0; | |
| char cmd[SMALL_BUFFER_MAX_SIZE] = ""; | |
| if (!T_FileStream_file_exists(installDir)) { | |
| UErrorCode status = U_ZERO_ERROR; | |
| uprv_mkdir(installDir, &status); | |
| if (U_FAILURE(status)) { | |
| fprintf(stderr, "Error creating installation directory: %s\n", installDir); | |
| return -1; | |
| } | |
| } | |
| #ifndef U_WINDOWS_WITH_MSVC | |
| char buffer[SMALL_BUFFER_MAX_SIZE] = ""; | |
| int32_t bufferLength = 0; | |
| FileStream *f = T_FileStream_open(fileListName, "r"); | |
| if (f != NULL) { | |
| for(;;) { | |
| if (T_FileStream_readLine(f, buffer, SMALL_BUFFER_MAX_SIZE) != NULL) { | |
| bufferLength = static_cast<int32_t>(uprv_strlen(buffer)); | |
| /* Remove new line character. */ | |
| if (bufferLength > 0) { | |
| buffer[bufferLength-1] = 0; | |
| } | |
| auto ret = snprintf(cmd, | |
| SMALL_BUFFER_MAX_SIZE, | |
| "%s %s%s%s %s%s%s", | |
| pkgDataFlags[INSTALL_CMD], | |
| srcDir, PKGDATA_FILE_SEP_STRING, buffer, | |
| installDir, PKGDATA_FILE_SEP_STRING, buffer); | |
| (void)ret; | |
| U_ASSERT(0 <= ret && ret < SMALL_BUFFER_MAX_SIZE); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Failed to install data file with command: %s\n", cmd); | |
| break; | |
| } | |
| } else { | |
| if (!T_FileStream_eof(f)) { | |
| fprintf(stderr, "Failed to read line from file: %s\n", fileListName); | |
| result = -1; | |
| } | |
| break; | |
| } | |
| } | |
| T_FileStream_close(f); | |
| } else { | |
| result = -1; | |
| fprintf(stderr, "Unable to open list file: %s\n", fileListName); | |
| } | |
| #else | |
| sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, srcDir, installDir, WIN_INSTALL_CMD_FLAGS); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Failed to install data file with command: %s\n", cmd); | |
| } | |
| #endif | |
| return result; | |
| } | |
| /* Archiving of the library file may be needed depending on the platform and options given. | |
| * If archiving is not needed, copy over the library file name. | |
| */ | |
| static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt) { | |
| int32_t result = 0; | |
| char cmd[LARGE_BUFFER_MAX_SIZE]; | |
| /* If the shared object suffix and the final object suffix is different and the final object suffix and the | |
| * archive file suffix is the same, then the final library needs to be archived. | |
| */ | |
| if (uprv_strcmp(pkgDataFlags[SOBJ_EXT], pkgDataFlags[SO_EXT]) != 0 && uprv_strcmp(pkgDataFlags[A_EXT], pkgDataFlags[SO_EXT]) == 0) { | |
| sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s.%s", | |
| libFileNames[LIB_FILE], | |
| pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "", | |
| reverseExt ? version : pkgDataFlags[SO_EXT], | |
| reverseExt ? pkgDataFlags[SO_EXT] : version); | |
| sprintf(cmd, "%s %s %s%s %s%s", | |
| pkgDataFlags[AR], | |
| pkgDataFlags[ARFLAGS], | |
| targetDir, | |
| libFileNames[LIB_FILE_VERSION], | |
| targetDir, | |
| libFileNames[LIB_FILE_VERSION_TMP]); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd); | |
| return result; | |
| } | |
| sprintf(cmd, "%s %s%s", | |
| pkgDataFlags[RANLIB], | |
| targetDir, | |
| libFileNames[LIB_FILE_VERSION]); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd); | |
| return result; | |
| } | |
| /* Remove unneeded library file. */ | |
| sprintf(cmd, "%s %s%s", | |
| RM_CMD, | |
| targetDir, | |
| libFileNames[LIB_FILE_VERSION_TMP]); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd); | |
| return result; | |
| } | |
| } else { | |
| uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]); | |
| } | |
| return result; | |
| } | |
| /* | |
| * Using the compiler information from the configuration file set by -O option, generate the library file. | |
| * command may be given to allow for a larger buffer for cmd. | |
| */ | |
| static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command, UBool specialHandling) { | |
| int32_t result = 0; | |
| char *cmd = NULL; | |
| UBool freeCmd = FALSE; | |
| int32_t length = 0; | |
| (void)specialHandling; // Suppress unused variable compiler warnings on platforms where all usage | |
| // of this parameter is #ifdefed out. | |
| /* This is necessary because if packaging is done without assembly code, objectFile might be extremely large | |
| * containing many object files and so the calling function should supply a command buffer that is large | |
| * enough to handle this. Otherwise, use the default size. | |
| */ | |
| if (command != NULL) { | |
| cmd = command; | |
| } | |
| if (IN_STATIC_MODE(mode)) { | |
| if (cmd == NULL) { | |
| length = static_cast<int32_t>(uprv_strlen(pkgDataFlags[AR]) + uprv_strlen(pkgDataFlags[ARFLAGS]) + uprv_strlen(targetDir) + | |
| uprv_strlen(libFileNames[LIB_FILE_VERSION]) + uprv_strlen(objectFile) + uprv_strlen(pkgDataFlags[RANLIB]) + BUFFER_PADDING_SIZE); | |
| if ((cmd = (char *)uprv_malloc(sizeof(char) * length)) == NULL) { | |
| fprintf(stderr, "Unable to allocate memory for command.\n"); | |
| return -1; | |
| } | |
| freeCmd = TRUE; | |
| } | |
| sprintf(cmd, "%s %s %s%s %s", | |
| pkgDataFlags[AR], | |
| pkgDataFlags[ARFLAGS], | |
| targetDir, | |
| libFileNames[LIB_FILE_VERSION], | |
| objectFile); | |
| result = runCommand(cmd); | |
| if (result == 0) { | |
| sprintf(cmd, "%s %s%s", | |
| pkgDataFlags[RANLIB], | |
| targetDir, | |
| libFileNames[LIB_FILE_VERSION]); | |
| result = runCommand(cmd); | |
| } | |
| } else /* if (IN_DLL_MODE(mode)) */ { | |
| if (cmd == NULL) { | |
| length = static_cast<int32_t>(uprv_strlen(pkgDataFlags[GENLIB]) + uprv_strlen(pkgDataFlags[LDICUDTFLAGS]) + | |
| ((uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_VERSION_TMP])) * 2) + | |
| uprv_strlen(objectFile) + uprv_strlen(pkgDataFlags[LD_SONAME]) + | |
| uprv_strlen(pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR]) + | |
| uprv_strlen(pkgDataFlags[RPATH_FLAGS]) + uprv_strlen(pkgDataFlags[BIR_FLAGS]) + BUFFER_PADDING_SIZE); | |
| #if U_PLATFORM == U_PF_CYGWIN | |
| length += static_cast<int32_t>(uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_CYGWIN_VERSION])); | |
| #elif U_PLATFORM == U_PF_MINGW | |
| length += static_cast<int32_t>(uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_MINGW])); | |
| #endif | |
| if ((cmd = (char *)uprv_malloc(sizeof(char) * length)) == NULL) { | |
| fprintf(stderr, "Unable to allocate memory for command.\n"); | |
| return -1; | |
| } | |
| freeCmd = TRUE; | |
| } | |
| #if U_PLATFORM == U_PF_MINGW | |
| sprintf(cmd, "%s%s%s %s -o %s%s %s %s%s %s %s", | |
| pkgDataFlags[GENLIB], | |
| targetDir, | |
| libFileNames[LIB_FILE_MINGW], | |
| pkgDataFlags[LDICUDTFLAGS], | |
| targetDir, | |
| libFileNames[LIB_FILE_VERSION_TMP], | |
| #elif U_PLATFORM == U_PF_CYGWIN | |
| sprintf(cmd, "%s%s%s %s -o %s%s %s %s%s %s %s", | |
| pkgDataFlags[GENLIB], | |
| targetDir, | |
| libFileNames[LIB_FILE_VERSION_TMP], | |
| pkgDataFlags[LDICUDTFLAGS], | |
| targetDir, | |
| libFileNames[LIB_FILE_CYGWIN_VERSION], | |
| #elif U_PLATFORM == U_PF_AIX | |
| sprintf(cmd, "%s %s%s;%s %s -o %s%s %s %s%s %s %s", | |
| RM_CMD, | |
| targetDir, | |
| libFileNames[LIB_FILE_VERSION_TMP], | |
| pkgDataFlags[GENLIB], | |
| pkgDataFlags[LDICUDTFLAGS], | |
| targetDir, | |
| libFileNames[LIB_FILE_VERSION_TMP], | |
| #else | |
| sprintf(cmd, "%s %s -o %s%s %s %s%s %s %s", | |
| pkgDataFlags[GENLIB], | |
| pkgDataFlags[LDICUDTFLAGS], | |
| targetDir, | |
| libFileNames[LIB_FILE_VERSION_TMP], | |
| #endif | |
| objectFile, | |
| pkgDataFlags[LD_SONAME], | |
| pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR], | |
| pkgDataFlags[RPATH_FLAGS], | |
| pkgDataFlags[BIR_FLAGS]); | |
| /* Generate the library file. */ | |
| result = runCommand(cmd); | |
| #if U_PLATFORM == U_PF_OS390 | |
| char *env_tmp; | |
| char PDS_LibName[512]; | |
| char PDS_Name[512]; | |
| PDS_Name[0] = 0; | |
| PDS_LibName[0] = 0; | |
| if (specialHandling && uprv_strcmp(libFileNames[LIB_FILE],"libicudata") == 0) { | |
| if (env_tmp = getenv("ICU_PDS_NAME")) { | |
| sprintf(PDS_Name, "%s%s", | |
| env_tmp, | |
| "DA"); | |
| strcat(PDS_Name, getenv("ICU_PDS_NAME_SUFFIX")); | |
| } else if (env_tmp = getenv("PDS_NAME_PREFIX")) { | |
| sprintf(PDS_Name, "%s%s", | |
| env_tmp, | |
| U_ICU_VERSION_SHORT "DA"); | |
| } else { | |
| sprintf(PDS_Name, "%s%s", | |
| "IXMI", | |
| U_ICU_VERSION_SHORT "DA"); | |
| } | |
| } else if (!specialHandling && uprv_strcmp(libFileNames[LIB_FILE],"libicudata_stub") == 0) { | |
| if (env_tmp = getenv("ICU_PDS_NAME")) { | |
| sprintf(PDS_Name, "%s%s", | |
| env_tmp, | |
| "D1"); | |
| strcat(PDS_Name, getenv("ICU_PDS_NAME_SUFFIX")); | |
| } else if (env_tmp = getenv("PDS_NAME_PREFIX")) { | |
| sprintf(PDS_Name, "%s%s", | |
| env_tmp, | |
| U_ICU_VERSION_SHORT "D1"); | |
| } else { | |
| sprintf(PDS_Name, "%s%s", | |
| "IXMI", | |
| U_ICU_VERSION_SHORT "D1"); | |
| } | |
| } | |
| if (PDS_Name[0]) { | |
| sprintf(PDS_LibName,"%s%s%s%s%s", | |
| "\"//'", | |
| getenv("LOADMOD"), | |
| "(", | |
| PDS_Name, | |
| ")'\""); | |
| sprintf(cmd, "%s %s -o %s %s %s%s %s %s", | |
| pkgDataFlags[GENLIB], | |
| pkgDataFlags[LDICUDTFLAGS], | |
| PDS_LibName, | |
| objectFile, | |
| pkgDataFlags[LD_SONAME], | |
| pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR], | |
| pkgDataFlags[RPATH_FLAGS], | |
| pkgDataFlags[BIR_FLAGS]); | |
| result = runCommand(cmd); | |
| } | |
| #endif | |
| } | |
| if (result != 0) { | |
| fprintf(stderr, "Error generating library file. Failed command: %s\n", cmd); | |
| } | |
| if (freeCmd) { | |
| uprv_free(cmd); | |
| } | |
| return result; | |
| } | |
| static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath) { | |
| char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = ""; | |
| int32_t result = 0; | |
| int32_t length = 0; | |
| /* Remove the ending .s and replace it with .o for the new object file. */ | |
| uprv_strcpy(tempObjectFile, gencFilePath); | |
| tempObjectFile[uprv_strlen(tempObjectFile)-1] = 'o'; | |
| length = static_cast<int32_t>(uprv_strlen(pkgDataFlags[COMPILER]) + uprv_strlen(pkgDataFlags[LIBFLAGS]) | |
| + uprv_strlen(tempObjectFile) + uprv_strlen(gencFilePath) + BUFFER_PADDING_SIZE); | |
| LocalMemory<char> cmd((char *)uprv_malloc(sizeof(char) * length)); | |
| if (cmd.isNull()) { | |
| return -1; | |
| } | |
| /* Generate the object file. */ | |
| sprintf(cmd.getAlias(), "%s %s -o %s %s", | |
| pkgDataFlags[COMPILER], | |
| pkgDataFlags[LIBFLAGS], | |
| tempObjectFile, | |
| gencFilePath); | |
| result = runCommand(cmd.getAlias()); | |
| if (result != 0) { | |
| fprintf(stderr, "Error creating with assembly code. Failed command: %s\n", cmd.getAlias()); | |
| return result; | |
| } | |
| return pkg_generateLibraryFile(targetDir, mode, tempObjectFile); | |
| } | |
| #ifdef BUILD_DATA_WITHOUT_ASSEMBLY | |
| /* | |
| * Generation of the data library without assembly code needs to compile each data file | |
| * individually and then link it all together. | |
| * Note: Any update to the directory structure of the data needs to be reflected here. | |
| */ | |
| enum { | |
| DATA_PREFIX_BRKITR, | |
| DATA_PREFIX_COLL, | |
| DATA_PREFIX_CURR, | |
| DATA_PREFIX_LANG, | |
| DATA_PREFIX_RBNF, | |
| DATA_PREFIX_REGION, | |
| DATA_PREFIX_TRANSLIT, | |
| DATA_PREFIX_ZONE, | |
| DATA_PREFIX_UNIT, | |
| DATA_PREFIX_LENGTH | |
| }; | |
| const static char DATA_PREFIX[DATA_PREFIX_LENGTH][10] = { | |
| "brkitr", | |
| "coll", | |
| "curr", | |
| "lang", | |
| "rbnf", | |
| "region", | |
| "translit", | |
| "zone", | |
| "unit" | |
| }; | |
| static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode) { | |
| int32_t result = 0; | |
| CharList *list = o->filePaths; | |
| CharList *listNames = o->files; | |
| int32_t listSize = pkg_countCharList(list); | |
| char *buffer; | |
| char *cmd; | |
| char gencmnFile[SMALL_BUFFER_MAX_SIZE] = ""; | |
| char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = ""; | |
| #ifdef USE_SINGLE_CCODE_FILE | |
| char icudtAll[SMALL_BUFFER_MAX_SIZE] = ""; | |
| FileStream *icudtAllFile = NULL; | |
| sprintf(icudtAll, "%s%s%sall.c", | |
| o->tmpDir, | |
| PKGDATA_FILE_SEP_STRING, | |
| libFileNames[LIB_FILE]); | |
| /* Remove previous icudtall.c file. */ | |
| if (T_FileStream_file_exists(icudtAll) && (result = remove(icudtAll)) != 0) { | |
| fprintf(stderr, "Unable to remove old icudtall file: %s\n", icudtAll); | |
| return result; | |
| } | |
| if((icudtAllFile = T_FileStream_open(icudtAll, "w"))==NULL) { | |
| fprintf(stderr, "Unable to write to icudtall file: %s\n", icudtAll); | |
| return result; | |
| } | |
| #endif | |
| if (list == NULL || listNames == NULL) { | |
| /* list and listNames should never be NULL since we are looping through the CharList with | |
| * the given size. | |
| */ | |
| return -1; | |
| } | |
| if ((cmd = (char *)uprv_malloc((listSize + 2) * SMALL_BUFFER_MAX_SIZE)) == NULL) { | |
| fprintf(stderr, "Unable to allocate memory for cmd.\n"); | |
| return -1; | |
| } else if ((buffer = (char *)uprv_malloc((listSize + 1) * SMALL_BUFFER_MAX_SIZE)) == NULL) { | |
| fprintf(stderr, "Unable to allocate memory for buffer.\n"); | |
| uprv_free(cmd); | |
| return -1; | |
| } | |
| for (int32_t i = 0; i < (listSize + 1); i++) { | |
| const char *file ; | |
| const char *name; | |
| if (i == 0) { | |
| /* The first iteration calls the gencmn function and initailizes the buffer. */ | |
| createCommonDataFile(o->tmpDir, o->shortName, o->entryName, NULL, o->srcDir, o->comment, o->fileListFiles->str, 0, TRUE, o->verbose, gencmnFile); | |
| buffer[0] = 0; | |
| #ifdef USE_SINGLE_CCODE_FILE | |
| uprv_strcpy(tempObjectFile, gencmnFile); | |
| tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o'; | |
| sprintf(cmd, "%s %s -o %s %s", | |
| pkgDataFlags[COMPILER], | |
| pkgDataFlags[LIBFLAGS], | |
| tempObjectFile, | |
| gencmnFile); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| break; | |
| } | |
| sprintf(buffer, "%s",tempObjectFile); | |
| #endif | |
| } else { | |
| char newName[SMALL_BUFFER_MAX_SIZE]; | |
| char dataName[SMALL_BUFFER_MAX_SIZE]; | |
| char dataDirName[SMALL_BUFFER_MAX_SIZE]; | |
| const char *pSubstring; | |
| file = list->str; | |
| name = listNames->str; | |
| newName[0] = dataName[0] = 0; | |
| for (int32_t n = 0; n < DATA_PREFIX_LENGTH; n++) { | |
| dataDirName[0] = 0; | |
| sprintf(dataDirName, "%s%s", DATA_PREFIX[n], PKGDATA_FILE_SEP_STRING); | |
| /* If the name contains a prefix (indicating directory), alter the new name accordingly. */ | |
| pSubstring = uprv_strstr(name, dataDirName); | |
| if (pSubstring != NULL) { | |
| char newNameTmp[SMALL_BUFFER_MAX_SIZE] = ""; | |
| const char *p = name + uprv_strlen(dataDirName); | |
| for (int32_t i = 0;;i++) { | |
| if (p[i] == '.') { | |
| newNameTmp[i] = '_'; | |
| continue; | |
| } | |
| newNameTmp[i] = p[i]; | |
| if (p[i] == 0) { | |
| break; | |
| } | |
| } | |
| auto ret = snprintf(newName, | |
| SMALL_BUFFER_MAX_SIZE, | |
| "%s_%s", | |
| DATA_PREFIX[n], | |
| newNameTmp); | |
| (void)ret; | |
| U_ASSERT(0 <= ret && ret < SMALL_BUFFER_MAX_SIZE); | |
| ret = snprintf(dataName, | |
| SMALL_BUFFER_MAX_SIZE, | |
| "%s_%s", | |
| o->shortName, | |
| DATA_PREFIX[n]); | |
| (void)ret; | |
| U_ASSERT(0 <= ret && ret < SMALL_BUFFER_MAX_SIZE); | |
| } | |
| if (newName[0] != 0) { | |
| break; | |
| } | |
| } | |
| if(o->verbose) { | |
| printf("# Generating %s \n", gencmnFile); | |
| } | |
| writeCCode( | |
| file, | |
| o->tmpDir, | |
| dataName[0] != 0 ? dataName : o->shortName, | |
| newName[0] != 0 ? newName : NULL, | |
| gencmnFile, | |
| sizeof(gencmnFile)); | |
| #ifdef USE_SINGLE_CCODE_FILE | |
| sprintf(cmd, "#include \"%s\"\n", gencmnFile); | |
| T_FileStream_writeLine(icudtAllFile, cmd); | |
| /* don't delete the file */ | |
| #endif | |
| } | |
| #ifndef USE_SINGLE_CCODE_FILE | |
| uprv_strcpy(tempObjectFile, gencmnFile); | |
| tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o'; | |
| sprintf(cmd, "%s %s -o %s %s", | |
| pkgDataFlags[COMPILER], | |
| pkgDataFlags[LIBFLAGS], | |
| tempObjectFile, | |
| gencmnFile); | |
| result = runCommand(cmd); | |
| if (result != 0) { | |
| fprintf(stderr, "Error creating library without assembly code. Failed command: %s\n", cmd); | |
| break; | |
| } | |
| uprv_strcat(buffer, " "); | |
| uprv_strcat(buffer, tempObjectFile); | |
| #endif | |
| if (i > 0) { | |
| list = list->next; | |
| listNames = listNames->next; | |
| } | |
| } | |
| #ifdef USE_SINGLE_CCODE_FILE | |
| T_FileStream_close(icudtAllFile); | |
| uprv_strcpy(tempObjectFile, icudtAll); | |
| tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o'; | |
| sprintf(cmd, "%s %s -I. -o %s %s", | |
| pkgDataFlags[COMPILER], | |
| pkgDataFlags[LIBFLAGS], | |
| tempObjectFile, | |
| icudtAll); | |
| result = runCommand(cmd); | |
| if (result == 0) { | |
| uprv_strcat(buffer, " "); | |
| uprv_strcat(buffer, tempObjectFile); | |
| } else { | |
| fprintf(stderr, "Error creating library without assembly code. Failed command: %s\n", cmd); | |
| } | |
| #endif | |
| if (result == 0) { | |
| /* Generate the library file. */ | |
| #if U_PLATFORM == U_PF_OS390 | |
| result = pkg_generateLibraryFile(targetDir, mode, buffer, cmd, (o->pdsbuild && IN_DLL_MODE(mode))); | |
| #else | |
| result = pkg_generateLibraryFile(targetDir,mode, buffer, cmd); | |
| #endif | |
| } | |
| uprv_free(buffer); | |
| uprv_free(cmd); | |
| return result; | |
| } | |
| #endif | |
| #ifdef WINDOWS_WITH_MSVC | |
| #define LINK_CMD "link.exe /nologo /release /out:" | |
| #define LINK_FLAGS "/NXCOMPAT /DYNAMICBASE /DLL /NOENTRY /MANIFEST:NO /implib:" | |
| #define LINK_EXTRA_UWP_FLAGS "/APPCONTAINER " | |
| #define LINK_EXTRA_UWP_FLAGS_X86_ONLY "/SAFESEH " | |
| #define LINK_EXTRA_FLAGS_MACHINE "/MACHINE:" | |
| #define LIB_CMD "LIB.exe /nologo /out:" | |
| #define LIB_FILE "icudt.lib" | |
| #define LIB_EXT UDATA_LIB_SUFFIX | |
| #define DLL_EXT UDATA_SO_SUFFIX | |
| static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o) { | |
| int32_t result = 0; | |
| char cmd[LARGE_BUFFER_MAX_SIZE]; | |
| if (IN_STATIC_MODE(mode)) { | |
| char staticLibFilePath[SMALL_BUFFER_MAX_SIZE] = ""; | |
| #ifdef CYGWINMSVC | |
| sprintf(staticLibFilePath, "%s%s%s%s%s", | |
| o->targetDir, | |
| PKGDATA_FILE_SEP_STRING, | |
| pkgDataFlags[LIBPREFIX], | |
| o->libName, | |
| LIB_EXT); | |
| #else | |
| sprintf(staticLibFilePath, "%s%s%s%s%s", | |
| o->targetDir, | |
| PKGDATA_FILE_SEP_STRING, | |
| (strstr(o->libName, "icudt") ? "s" : ""), | |
| o->libName, | |
| LIB_EXT); | |
| #endif | |
| sprintf(cmd, "%s\"%s\" \"%s\"", | |
| LIB_CMD, | |
| staticLibFilePath, | |
| gencFilePath); | |
| } else if (IN_DLL_MODE(mode)) { | |
| char dllFilePath[SMALL_BUFFER_MAX_SIZE] = ""; | |
| char libFilePath[SMALL_BUFFER_MAX_SIZE] = ""; | |
| char resFilePath[SMALL_BUFFER_MAX_SIZE] = ""; | |
| char tmpResFilePath[SMALL_BUFFER_MAX_SIZE] = ""; | |
| #ifdef CYGWINMSVC | |
| uprv_strcpy(dllFilePath, o->targetDir); | |
| #else | |
| uprv_strcpy(dllFilePath, o->srcDir); | |
| #endif | |
| uprv_strcat(dllFilePath, PKGDATA_FILE_SEP_STRING); | |
| uprv_strcpy(libFilePath, dllFilePath); | |
| #ifdef CYGWINMSVC | |
| uprv_strcat(libFilePath, o->libName); | |
| uprv_strcat(libFilePath, ".lib"); | |
| uprv_strcat(dllFilePath, o->libName); | |
| uprv_strcat(dllFilePath, o->version); | |
| #else | |
| if (strstr(o->libName, "icudt")) { | |
| uprv_strcat(libFilePath, LIB_FILE); | |
| } else { | |
| uprv_strcat(libFilePath, o->libName); | |
| uprv_strcat(libFilePath, ".lib"); | |
| } | |
| uprv_strcat(dllFilePath, o->entryName); | |
| #endif | |
| uprv_strcat(dllFilePath, DLL_EXT); | |
| uprv_strcpy(tmpResFilePath, o->tmpDir); | |
| uprv_strcat(tmpResFilePath, PKGDATA_FILE_SEP_STRING); | |
| uprv_strcat(tmpResFilePath, ICUDATA_RES_FILE); | |
| if (T_FileStream_file_exists(tmpResFilePath)) { | |
| sprintf(resFilePath, "\"%s\"", tmpResFilePath); | |
| } | |
| /* Check if dll file and lib file exists and that it is not newer than genc file. */ | |
| if (!o->rebuild && (T_FileStream_file_exists(dllFilePath) && isFileModTimeLater(dllFilePath, gencFilePath)) && | |
| (T_FileStream_file_exists(libFilePath) && isFileModTimeLater(libFilePath, gencFilePath))) { | |
| if(o->verbose) { | |
| printf("# Not rebuilding %s - up to date.\n", gencFilePath); | |
| } | |
| return 0; | |
| } | |
| char extraFlags[SMALL_BUFFER_MAX_SIZE] = ""; | |
| #ifdef WINDOWS_WITH_MSVC | |
| if (options[WIN_UWP_BUILD].doesOccur) { | |
| uprv_strcat(extraFlags, LINK_EXTRA_UWP_FLAGS); | |
| if (options[WIN_DLL_ARCH].doesOccur) { | |
| if (uprv_strcmp(options[WIN_DLL_ARCH].value, "X86") == 0) { | |
| uprv_strcat(extraFlags, LINK_EXTRA_UWP_FLAGS_X86_ONLY); | |
| } | |
| } | |
| } | |
| if (options[WIN_DLL_ARCH].doesOccur) { | |
| uprv_strcat(extraFlags, LINK_EXTRA_FLAGS_MACHINE); | |
| uprv_strcat(extraFlags, options[WIN_DLL_ARCH].value); | |
| } | |
| #endif | |
| sprintf(cmd, "%s\"%s\" %s %s\"%s\" \"%s\" %s", | |
| LINK_CMD, | |
| dllFilePath, | |
| extraFlags, | |
| LINK_FLAGS, | |
| libFilePath, | |
| gencFilePath, | |
| resFilePath | |
| ); | |
| } | |
| result = runCommand(cmd, TRUE); | |
| if (result != 0) { | |
| fprintf(stderr, "Error creating Windows DLL library. Failed command: %s\n", cmd); | |
| } | |
| return result; | |
| } | |
| #endif | |
| static UPKGOptions *pkg_checkFlag(UPKGOptions *o) { | |
| #if U_PLATFORM == U_PF_AIX | |
| /* AIX needs a map file. */ | |
| char *flag = NULL; | |
| int32_t length = 0; | |
| char tmpbuffer[SMALL_BUFFER_MAX_SIZE]; | |
| const char MAP_FILE_EXT[] = ".map"; | |
| FileStream *f = NULL; | |
| char mapFile[SMALL_BUFFER_MAX_SIZE] = ""; | |
| int32_t start = -1; | |
| uint32_t count = 0; | |
| const char rm_cmd[] = "rm -f all ;"; | |
| flag = pkgDataFlags[GENLIB]; | |
| /* This portion of the code removes 'rm -f all' in the GENLIB. | |
| * Only occurs in AIX. | |
| */ | |
| if (uprv_strstr(flag, rm_cmd) != NULL) { | |
| char *tmpGenlibFlagBuffer = NULL; | |
| int32_t i, offset; | |
| length = static_cast<int32_t>(uprv_strlen(flag) + 1); | |
| tmpGenlibFlagBuffer = (char *)uprv_malloc(length); | |
| if (tmpGenlibFlagBuffer == NULL) { | |
| /* Memory allocation error */ | |
| fprintf(stderr,"Unable to allocate buffer of size: %d.\n", length); | |
| return NULL; | |
| } | |
| uprv_strcpy(tmpGenlibFlagBuffer, flag); | |
| offset = static_cast<int32_t>(uprv_strlen(rm_cmd)); | |
| for (i = 0; i < (length - offset); i++) { | |
| flag[i] = tmpGenlibFlagBuffer[offset + i]; | |
| } | |
| /* Zero terminate the string */ | |
| flag[i] = 0; | |
| uprv_free(tmpGenlibFlagBuffer); | |
| } | |
| flag = pkgDataFlags[BIR_FLAGS]; | |
| length = static_cast<int32_t>(uprv_strlen(pkgDataFlags[BIR_FLAGS])); | |
| for (int32_t i = 0; i < length; i++) { | |
| if (flag[i] == MAP_FILE_EXT[count]) { | |
| if (count == 0) { | |
| start = i; | |
| } | |
| count++; | |
| } else { | |
| count = 0; | |
| } | |
| if (count == uprv_strlen(MAP_FILE_EXT)) { | |
| break; | |
| } | |
| } | |
| if (start >= 0) { | |
| int32_t index = 0; | |
| for (int32_t i = 0;;i++) { | |
| if (i == start) { | |
| for (int32_t n = 0;;n++) { | |
| if (o->shortName[n] == 0) { | |
| break; | |
| } | |
| tmpbuffer[index++] = o->shortName[n]; | |
| } | |
| } | |
| tmpbuffer[index++] = flag[i]; | |
| if (flag[i] == 0) { | |
| break; | |
| } | |
| } | |
| uprv_memset(flag, 0, length); | |
| uprv_strcpy(flag, tmpbuffer); | |
| uprv_strcpy(mapFile, o->shortName); | |
| uprv_strcat(mapFile, MAP_FILE_EXT); | |
| f = T_FileStream_open(mapFile, "w"); | |
| if (f == NULL) { | |
| fprintf(stderr,"Unable to create map file: %s.\n", mapFile); | |
| return NULL; | |
| } else { | |
| sprintf(tmpbuffer, "%s%s ", o->entryName, UDATA_CMN_INTERMEDIATE_SUFFIX); | |
| T_FileStream_writeLine(f, tmpbuffer); | |
| T_FileStream_close(f); | |
| } | |
| } | |
| #elif U_PLATFORM == U_PF_CYGWIN || U_PLATFORM == U_PF_MINGW | |
| /* Cygwin needs to change flag options. */ | |
| char *flag = NULL; | |
| int32_t length = 0; | |
| flag = pkgDataFlags[GENLIB]; | |
| length = static_cast<int32_t>(uprv_strlen(pkgDataFlags[GENLIB])); | |
| int32_t position = length - 1; | |
| for(;position >= 0;position--) { | |
| if (flag[position] == '=') { | |
| position++; | |
| break; | |
| } | |
| } | |
| uprv_memset(flag + position, 0, length - position); | |
| #elif U_PLATFORM == U_PF_OS400 | |
| /* OS/400 needs to fix the ld options (swap single quote with double quote) */ | |
| char *flag = NULL; | |
| int32_t length = 0; | |
| flag = pkgDataFlags[GENLIB]; | |
| length = static_cast<int32_t>(uprv_strlen(pkgDataFlags[GENLIB])); | |
| int32_t position = length - 1; | |
| for(int32_t i = 0; i < length; i++) { | |
| if (flag[i] == '\'') { | |
| flag[i] = '\"'; | |
| } | |
| } | |
| #endif | |
| // Don't really need a return value, just need to stop compiler warnings about | |
| // the unused parameter 'o' on platforms where it is not otherwise used. | |
| return o; | |
| } | |
| static void loadLists(UPKGOptions *o, UErrorCode *status) | |
| { | |
| CharList *l, *tail = NULL, *tail2 = NULL; | |
| FileStream *in; | |
| char line[16384]; | |
| char *linePtr, *lineNext; | |
| const uint32_t lineMax = 16300; | |
| char *tmp; | |
| int32_t tmpLength = 0; | |
| char *s; | |
| int32_t ln=0; /* line number */ | |
| for(l = o->fileListFiles; l; l = l->next) { | |
| if(o->verbose) { | |
| fprintf(stdout, "# pkgdata: Reading %s..\n", l->str); | |
| } | |
| /* TODO: stdin */ | |
| in = T_FileStream_open(l->str, "r"); /* open files list */ | |
| if(!in) { | |
| fprintf(stderr, "Error opening <%s>.\n", l->str); | |
| *status = U_FILE_ACCESS_ERROR; | |
| return; | |
| } | |
| while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) { /* for each line */ | |
| ln++; | |
| if(uprv_strlen(line)>lineMax) { | |
| fprintf(stderr, "%s:%d - line too long (over %d chars)\n", l->str, (int)ln, (int)lineMax); | |
| exit(1); | |
| } | |
| /* remove spaces at the beginning */ | |
| linePtr = line; | |
| /* On z/OS, disable call to isspace (#9996). Investigate using uprv_isspace instead (#9999) */ | |
| #if U_PLATFORM != U_PF_OS390 | |
| while(isspace(*linePtr)) { | |
| linePtr++; | |
| } | |
| #endif | |
| s=linePtr; | |
| /* remove trailing newline characters */ | |
| while(*s!=0) { | |
| if(*s=='\r' || *s=='\n') { | |
| *s=0; | |
| break; | |
| } | |
| ++s; | |
| } | |
| if((*linePtr == 0) || (*linePtr == '#')) { | |
| continue; /* comment or empty line */ | |
| } | |
| /* Now, process the line */ | |
| lineNext = NULL; | |
| while(linePtr && *linePtr) { /* process space-separated items */ | |
| while(*linePtr == ' ') { | |
| linePtr++; | |
| } | |
| /* Find the next quote */ | |
| if(linePtr[0] == '"') | |
| { | |
| lineNext = uprv_strchr(linePtr+1, '"'); | |
| if(lineNext == NULL) { | |
| fprintf(stderr, "%s:%d - missing trailing double quote (\")\n", | |
| l->str, (int)ln); | |
| exit(1); | |
| } else { | |
| lineNext++; | |
| if(*lineNext) { | |
| if(*lineNext != ' ') { | |
| fprintf(stderr, "%s:%d - malformed quoted line at position %d, expected ' ' got '%c'\n", | |
| l->str, (int)ln, (int)(lineNext-line), (*lineNext)?*lineNext:'0'); | |
| exit(1); | |
| } | |
| *lineNext = 0; | |
| lineNext++; | |
| } | |
| } | |
| } else { | |
| lineNext = uprv_strchr(linePtr, ' '); | |
| if(lineNext) { | |
| *lineNext = 0; /* terminate at space */ | |
| lineNext++; | |
| } | |
| } | |
| /* add the file */ | |
| s = (char*)getLongPathname(linePtr); | |
| /* normal mode.. o->files is just the bare list without package names */ | |
| o->files = pkg_appendToList(o->files, &tail, uprv_strdup(linePtr)); | |
| if(uprv_pathIsAbsolute(s) || s[0] == '.') { | |
| 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); | |
| exit(U_ILLEGAL_ARGUMENT_ERROR); | |
| } | |
| /* The +5 is to add a little extra space for, among other things, PKGDATA_FILE_SEP_STRING */ | |
| tmpLength = static_cast<int32_t>(uprv_strlen(o->srcDir) + uprv_strlen(s) + 5); | |
| if((tmp = (char *)uprv_malloc(tmpLength)) == NULL) { | |
| fprintf(stderr, "pkgdata: Error: Unable to allocate tmp buffer size: %d\n", tmpLength); | |
| exit(U_MEMORY_ALLOCATION_ERROR); | |
| } | |
| uprv_strcpy(tmp, o->srcDir); | |
| uprv_strcat(tmp, o->srcDir[uprv_strlen(o->srcDir)-1] == U_FILE_SEP_CHAR ? "" : PKGDATA_FILE_SEP_STRING); | |
| uprv_strcat(tmp, s); | |
| o->filePaths = pkg_appendToList(o->filePaths, &tail2, tmp); | |
| linePtr = lineNext; | |
| } /* for each entry on line */ | |
| } /* for each line */ | |
| T_FileStream_close(in); | |
| } /* for each file list file */ | |
| } | |
| /* Helper for pkg_getPkgDataPath() */ | |
| #if U_HAVE_POPEN | |
| static UBool getPkgDataPath(const char *cmd, UBool verbose, char *buf, size_t items) { | |
| icu::CharString cmdBuf; | |
| UErrorCode status = U_ZERO_ERROR; | |
| LocalPipeFilePointer p; | |
| size_t n; | |
| cmdBuf.append(cmd, status); | |
| if (verbose) { | |
| fprintf(stdout, "# Calling: %s\n", cmdBuf.data()); | |
| } | |
| p.adoptInstead( popen(cmdBuf.data(), "r") ); | |
| if (p.isNull() || (n = fread(buf, 1, items-1, p.getAlias())) <= 0) { | |
| fprintf(stderr, "%s: Error calling '%s'\n", progname, cmd); | |
| *buf = 0; | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| #endif | |
| /* Get path to pkgdata.inc. Try pkg-config first, falling back to icu-config. */ | |
| static int32_t pkg_getPkgDataPath(UBool verbose, UOption *option) { | |
| #if U_HAVE_POPEN | |
| static char buf[512] = ""; | |
| UBool pkgconfigIsValid = TRUE; | |
| const char *pkgconfigCmd = "pkg-config --variable=pkglibdir icu-uc"; | |
| const char *icuconfigCmd = "icu-config --incpkgdatafile"; | |
| const char *pkgdata = "pkgdata.inc"; | |
| if (!getPkgDataPath(pkgconfigCmd, verbose, buf, UPRV_LENGTHOF(buf))) { | |
| if (!getPkgDataPath(icuconfigCmd, verbose, buf, UPRV_LENGTHOF(buf))) { | |
| fprintf(stderr, "%s: icu-config not found. Fix PATH or specify -O option\n", progname); | |
| return -1; | |
| } | |
| pkgconfigIsValid = FALSE; | |
| } | |
| for (int32_t length = strlen(buf) - 1; length >= 0; length--) { | |
| if (buf[length] == '\n' || buf[length] == ' ') { | |
| buf[length] = 0; | |
| } else { | |
| break; | |
| } | |
| } | |
| if (!*buf) { | |
| fprintf(stderr, "%s: Unable to locate pkgdata.inc. Unable to parse the results of '%s'. Check paths or use the -O option to specify the path to pkgdata.inc.\n", progname, pkgconfigIsValid ? pkgconfigCmd : icuconfigCmd); | |
| return -1; | |
| } | |
| if (pkgconfigIsValid) { | |
| uprv_strcat(buf, U_FILE_SEP_STRING); | |
| uprv_strcat(buf, pkgdata); | |
| } | |
| buf[strlen(buf)] = 0; | |
| option->value = buf; | |
| option->doesOccur = TRUE; | |
| return 0; | |
| #else | |
| return -1; | |
| #endif | |
| } | |
| #ifdef CAN_WRITE_OBJ_CODE | |
| /* Create optMatchArch for genccode architecture detection */ | |
| static void pkg_createOptMatchArch(char *optMatchArch) { | |
| #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) | |
| const char* code = "void oma(){}"; | |
| const char* source = "oma.c"; | |
| const char* obj = "oma.obj"; | |
| FileStream* stream = NULL; | |
| stream = T_FileStream_open(source,"w"); | |
| if (stream != NULL) { | |
| T_FileStream_writeLine(stream, code); | |
| T_FileStream_close(stream); | |
| char cmd[LARGE_BUFFER_MAX_SIZE]; | |
| sprintf(cmd, "%s %s -o %s", | |
| pkgDataFlags[COMPILER], | |
| source, | |
| obj); | |
| if (runCommand(cmd) == 0){ | |
| sprintf(optMatchArch, "%s", obj); | |
| } | |
| else { | |
| fprintf(stderr, "Failed to compile %s\n", source); | |
| } | |
| if(!T_FileStream_remove(source)){ | |
| fprintf(stderr, "T_FileStream_remove failed to delete %s\n", source); | |
| } | |
| } | |
| else { | |
| fprintf(stderr, "T_FileStream_open failed to open %s for writing\n", source); | |
| } | |
| #endif | |
| } | |
| static void pkg_destroyOptMatchArch(char *optMatchArch) { | |
| if(T_FileStream_file_exists(optMatchArch) && !T_FileStream_remove(optMatchArch)){ | |
| fprintf(stderr, "T_FileStream_remove failed to delete %s\n", optMatchArch); | |
| } | |
| } | |
| #endif |