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