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