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