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