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