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