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