Home | History | Annotate | Download | only in scripts
      1 #!/usr/bin/perl
      2 
      3 # This script will take a number ($ENV{SCRIPT_INPUT_FILE_COUNT}) of static archive files
      4 # and pull them apart into object files. These object files will be placed in a directory
      5 # named the same as the archive itself without the extension. Each object file will then
      6 # get renamed to start with the archive name and a '-' character (for archive.a(object.o)
      7 # the object file would becomde archive-object.o. Then all object files are re-made into
      8 # a single static library. This can help avoid name collisions when different archive
      9 # files might contain object files with the same name.
     10 
     11 use strict;
     12 use File::Basename;
     13 use File::Glob ':glob';
     14 use List::Util qw[min max];
     15 
     16 our $llvm_srcroot = $ENV{SCRIPT_INPUT_FILE_0};
     17 our $llvm_dstroot = $ENV{SCRIPT_INPUT_FILE_1};
     18 
     19 our $llvm_clang_outfile = $ENV{SCRIPT_OUTPUT_FILE_0};
     20 our ($llvm_clang_basename, $llvm_clang_dirname) = fileparse ($llvm_clang_outfile);
     21 
     22 our $llvm_configuration = $ENV{LLVM_CONFIGURATION};
     23 
     24 our $llvm_revision = "HEAD";
     25 our $clang_revision = "HEAD";
     26 
     27 our $SRCROOT = "$ENV{SRCROOT}";
     28 our @archs = split (/\s+/, $ENV{ARCHS});
     29 my $os_release = 11;
     30 
     31 my $original_env_path = $ENV{PATH};
     32 
     33 our %llvm_config_info = (
     34     'Debug'         => { configure_options => '--disable-optimized --disable-assertions --enable-libcpp', make_options => 'DEBUG_SYMBOLS=1'},
     35     'Debug+Asserts' => { configure_options => '--disable-optimized --enable-assertions --enable-libcpp' , make_options => 'DEBUG_SYMBOLS=1'},
     36     'Release'       => { configure_options => '--enable-optimized --disable-assertions --enable-libcpp' , make_options => ''},
     37     'Release+Debug' => { configure_options => '--enable-optimized --disable-assertions --enable-libcpp' , make_options => 'DEBUG_SYMBOLS=1'},
     38     'Release+Asserts' => { configure_options => '--enable-optimized --enable-assertions --enable-libcpp' , make_options => ''},
     39 );
     40 
     41 our $llvm_config_href = undef;
     42 if (exists $llvm_config_info{"$llvm_configuration"})
     43 {
     44     $llvm_config_href = $llvm_config_info{$llvm_configuration};
     45 }
     46 else
     47 {
     48     die "Unsupported LLVM configuration: '$llvm_configuration'\n";
     49 }
     50 
     51 our @archive_files = (
     52     "$llvm_configuration/lib/libclang.a",
     53     "$llvm_configuration/lib/libclangAnalysis.a",
     54     "$llvm_configuration/lib/libclangAST.a",
     55     "$llvm_configuration/lib/libclangBasic.a",
     56     "$llvm_configuration/lib/libclangCodeGen.a",
     57     "$llvm_configuration/lib/libclangEdit.a",
     58     "$llvm_configuration/lib/libclangFrontend.a",
     59     "$llvm_configuration/lib/libclangDriver.a",
     60     "$llvm_configuration/lib/libclangLex.a",
     61     "$llvm_configuration/lib/libclangParse.a",
     62     "$llvm_configuration/lib/libclangSema.a",
     63     "$llvm_configuration/lib/libclangSerialization.a",
     64     "$llvm_configuration/lib/libLLVMAnalysis.a",
     65     "$llvm_configuration/lib/libLLVMArchive.a",
     66     "$llvm_configuration/lib/libLLVMARMAsmParser.a",
     67     "$llvm_configuration/lib/libLLVMARMAsmPrinter.a",
     68     "$llvm_configuration/lib/libLLVMARMCodeGen.a",
     69     "$llvm_configuration/lib/libLLVMARMDesc.a",
     70     "$llvm_configuration/lib/libLLVMARMDisassembler.a",
     71     "$llvm_configuration/lib/libLLVMARMInfo.a",
     72     "$llvm_configuration/lib/libLLVMAsmParser.a",
     73     "$llvm_configuration/lib/libLLVMAsmPrinter.a",
     74     "$llvm_configuration/lib/libLLVMBitReader.a",
     75     "$llvm_configuration/lib/libLLVMBitWriter.a",
     76     "$llvm_configuration/lib/libLLVMCodeGen.a",
     77     "$llvm_configuration/lib/libLLVMCore.a",
     78     "$llvm_configuration/lib/libLLVMExecutionEngine.a",
     79     "$llvm_configuration/lib/libLLVMInstCombine.a",
     80     "$llvm_configuration/lib/libLLVMInstrumentation.a",
     81     "$llvm_configuration/lib/libLLVMipa.a",
     82     "$llvm_configuration/lib/libLLVMInterpreter.a",
     83     "$llvm_configuration/lib/libLLVMipo.a",
     84     "$llvm_configuration/lib/libLLVMJIT.a",
     85     "$llvm_configuration/lib/libLLVMLinker.a",
     86     "$llvm_configuration/lib/libLLVMMC.a",
     87     "$llvm_configuration/lib/libLLVMMCParser.a",
     88     "$llvm_configuration/lib/libLLVMMCDisassembler.a",
     89     "$llvm_configuration/lib/libLLVMMCJIT.a",
     90     "$llvm_configuration/lib/libLLVMObject.a",
     91     "$llvm_configuration/lib/libLLVMOption.a",
     92     "$llvm_configuration/lib/libLLVMRuntimeDyld.a",
     93     "$llvm_configuration/lib/libLLVMScalarOpts.a",
     94     "$llvm_configuration/lib/libLLVMSelectionDAG.a",
     95     "$llvm_configuration/lib/libLLVMSupport.a",
     96     "$llvm_configuration/lib/libLLVMTarget.a",
     97     "$llvm_configuration/lib/libLLVMTransformUtils.a",
     98     "$llvm_configuration/lib/libLLVMX86AsmParser.a",
     99     "$llvm_configuration/lib/libLLVMX86AsmPrinter.a",
    100     "$llvm_configuration/lib/libLLVMX86CodeGen.a",
    101     "$llvm_configuration/lib/libLLVMX86Desc.a",
    102     "$llvm_configuration/lib/libLLVMX86Disassembler.a",
    103     "$llvm_configuration/lib/libLLVMX86Info.a",
    104     "$llvm_configuration/lib/libLLVMX86Utils.a",
    105 );
    106 
    107 if (-e "$llvm_srcroot/lib")
    108 {
    109     print "Using existing llvm sources in: '$llvm_srcroot'\n";
    110     print "Using standard LLVM build directory:\n  SRC = '$llvm_srcroot'\n  DST = '$llvm_dstroot'\n";
    111 }
    112 else
    113 {
    114     print "Checking out llvm sources from revision $llvm_revision...\n";
    115     do_command ("cd '$SRCROOT' && svn co --quiet --revision $llvm_revision http://llvm.org/svn/llvm-project/llvm/trunk llvm", "checking out llvm from repository", 1);
    116     print "Checking out clang sources from revision $clang_revision...\n";
    117     do_command ("cd '$llvm_srcroot/tools' && svn co --quiet --revision $clang_revision http://llvm.org/svn/llvm-project/cfe/trunk clang", "checking out clang from repository", 1);
    118     print "Applying any local patches to LLVM/Clang...";
    119 
    120     my @llvm_patches = bsd_glob("$ENV{SRCROOT}/scripts/llvm.*.diff");
    121     foreach my $patch (@llvm_patches)
    122     {
    123         do_command ("cd '$llvm_srcroot' && patch -p0 < $patch");
    124     }
    125 
    126     my @clang_patches = bsd_glob("$ENV{SRCROOT}/scripts/clang.*.diff");
    127     foreach my $patch (@clang_patches)
    128     {
    129         do_command ("cd '$llvm_srcroot/tools/clang' && patch -p0 < $patch");
    130     }
    131 }
    132 
    133 # If our output file already exists then we need not generate it again.
    134 if (-e $llvm_clang_outfile)
    135 {
    136     exit 0;
    137 }
    138 
    139 
    140 # Get our options
    141 
    142 our $debug = 1;
    143 
    144 sub parallel_guess
    145 {
    146     my $cpus = `sysctl -n hw.availcpu`;
    147     chomp ($cpus);
    148     my $memsize = `sysctl -n hw.memsize`;
    149     chomp ($memsize);
    150     my $max_cpus_by_memory = int($memsize / (750 * 1024 * 1024));
    151     return min($max_cpus_by_memory, $cpus);
    152 }
    153 
    154 sub build_llvm
    155 {
    156     #my $extra_svn_options = $debug ? "" : "--quiet";
    157     # Make the llvm build directory
    158     my $arch_idx = 0;
    159     foreach my $arch (@archs)
    160     {
    161         my $llvm_dstroot_arch = "${llvm_dstroot}/${arch}";
    162 
    163         # if the arch destination root exists we have already built it
    164         my $do_configure = 0;
    165         my $do_make = 0;
    166         my $is_arm = $arch =~ /^arm/;
    167 
    168         my $llvm_dstroot_arch_archive = "$llvm_dstroot_arch/$llvm_clang_basename";
    169         print "LLVM architecture root for ${arch} exists at '$llvm_dstroot_arch'...";
    170         if (-e $llvm_dstroot_arch)
    171         {
    172             print "YES\n";
    173             $do_configure = !-e "$llvm_dstroot_arch/config.log";
    174 
    175             # dstroot for llvm build exists, make sure all .a files are built
    176             for my $llvm_lib (@archive_files)
    177             {
    178                 if (!-e "$llvm_dstroot_arch/$llvm_lib")
    179                 {
    180                     print "missing archive: '$llvm_dstroot_arch/$llvm_lib'\n";
    181                     $do_make = 1;
    182                 }
    183             }
    184             if (!-e $llvm_dstroot_arch_archive)
    185             {
    186                 $do_make = 1;
    187             }
    188             else
    189             {
    190                 print "LLVM architecture archive for ${arch} is '$llvm_dstroot_arch_archive'\n";
    191             }
    192         }
    193         else
    194         {
    195             print "NO\n";
    196             do_command ("mkdir -p '$llvm_dstroot_arch'", "making llvm build directory '$llvm_dstroot_arch'", 1);
    197             $do_configure = 1;
    198             $do_make = 1;
    199 
    200             if ($is_arm)
    201             {
    202                 my $llvm_dstroot_arch_bin = "${llvm_dstroot_arch}/bin";
    203                 if (!-d $llvm_dstroot_arch_bin)
    204                 {
    205                     do_command ("mkdir -p '$llvm_dstroot_arch_bin'", "making llvm build arch bin directory '$llvm_dstroot_arch_bin'", 1);
    206                     my @tools = ("ar", "nm", "ranlib", "strip", "lipo", "ld", "as");
    207                     my $script_mode = 0755;
    208                     my $prog;
    209                     for $prog (@tools)
    210                     {
    211                         chomp(my $actual_prog_path = `xcrun -sdk '$ENV{SDKROOT}' -find ${prog}`);
    212                         symlink($actual_prog_path, "$llvm_dstroot_arch_bin/${prog}");
    213                         my $script_prog_path = "$llvm_dstroot_arch_bin/arm-apple-darwin${os_release}-${prog}";
    214                         open (SCRIPT, ">$script_prog_path") or die "Can't open $! for writing...\n";
    215                         print SCRIPT "#!/bin/sh\nexec '$actual_prog_path' \"\$\@\"\n";
    216                         close (SCRIPT);
    217                         chmod($script_mode, $script_prog_path);
    218                     }
    219                     #  Tools that must have the "-arch" and "-sysroot" specified
    220                     my @arch_sysroot_tools = ("clang", "clang++", "gcc", "g++");
    221                     for $prog (@arch_sysroot_tools)
    222                     {
    223                         chomp(my $actual_prog_path = `xcrun -sdk '$ENV{SDKROOT}' -find ${prog}`);
    224                         symlink($actual_prog_path, "$llvm_dstroot_arch_bin/${prog}");
    225                         my $script_prog_path = "$llvm_dstroot_arch_bin/arm-apple-darwin${os_release}-${prog}";
    226                         open (SCRIPT, ">$script_prog_path") or die "Can't open $! for writing...\n";
    227                         print SCRIPT "#!/bin/sh\nexec '$actual_prog_path' -arch ${arch} -isysroot '$ENV{SDKROOT}' \"\$\@\"\n";
    228                         close (SCRIPT);
    229                         chmod($script_mode, $script_prog_path);
    230                     }
    231                     my $new_path = "$original_env_path:$llvm_dstroot_arch_bin";
    232                     print "Setting new environment PATH = '$new_path'\n";
    233                     $ENV{PATH} = $new_path;
    234                 }
    235             }
    236         }
    237 
    238         if ($do_configure)
    239         {
    240             # Build llvm and clang
    241             print "Configuring clang ($arch) in '$llvm_dstroot_arch'...\n";
    242             my $lldb_configuration_options = "--enable-targets=x86_64,arm $llvm_config_href->{configure_options}";
    243 
    244             if ($is_arm)
    245             {
    246                 $lldb_configuration_options .= " --host=arm-apple-darwin${os_release} --target=arm-apple-darwin${os_release} --build=i686-apple-darwin${os_release} --program-prefix=\"\"";
    247             }
    248             else
    249             {
    250                 $lldb_configuration_options .= " --build=$arch-apple-darwin${os_release}";
    251             }
    252 			if ($is_arm)
    253 			{
    254 				# Unset "SDKROOT" for ARM builds
    255 	            do_command ("cd '$llvm_dstroot_arch' && unset SDKROOT && '$llvm_srcroot/configure' $lldb_configuration_options",
    256 	                        "configuring llvm build", 1);				
    257 			}
    258 			else
    259 			{
    260 	            do_command ("cd '$llvm_dstroot_arch' && '$llvm_srcroot/configure' $lldb_configuration_options",
    261 	                        "configuring llvm build", 1);								
    262 			}
    263         }
    264 
    265         if ($do_make)
    266         {
    267             # Build llvm and clang
    268             my $num_cpus = parallel_guess();
    269             print "Building clang using $num_cpus cpus ($arch)...\n";
    270             my $extra_make_flags = '';
    271             if ($is_arm)
    272             {
    273                 $extra_make_flags = "UNIVERSAL=1 UNIVERSAL_ARCH=${arch} UNIVERSAL_SDK_PATH='$ENV{SDKROOT}' SDKROOT=";
    274             }
    275             do_command ("cd '$llvm_dstroot_arch' && make -j$num_cpus clang-only VERBOSE=1 $llvm_config_href->{make_options} NO_RUNTIME_LIBS=1 PROJECT_NAME='llvm' $extra_make_flags", "making llvm and clang", 1);
    276             do_command ("cd '$llvm_dstroot_arch' && make -j$num_cpus tools-only VERBOSE=1 $llvm_config_href->{make_options} NO_RUNTIME_LIBS=1 PROJECT_NAME='llvm' $extra_make_flags EDIS_VERSION=1", "making libedis", 1);
    277             # Combine all .o files from a bunch of static libraries from llvm
    278             # and clang into a single .a file.
    279             create_single_llvm_archive_for_arch ($llvm_dstroot_arch, 1);
    280         }
    281 
    282         ++$arch_idx;
    283     }
    284 }
    285 
    286 #----------------------------------------------------------------------
    287 # quote the path if needed and realpath it if the -r option was
    288 # specified
    289 #----------------------------------------------------------------------
    290 sub finalize_path
    291 {
    292     my $path = shift;
    293     # Realpath all paths that don't start with "/"
    294     $path =~ /^[^\/]/ and $path = abs_path($path);
    295 
    296     # Quote the path if asked to, or if there are special shell characters
    297     # in the path name
    298     my $has_double_quotes = $path =~ /["]/;
    299     my $has_single_quotes = $path =~ /[']/;
    300     my $needs_quotes = $path =~ /[ \$\&\*'"]/;
    301     if ($needs_quotes)
    302     {
    303         # escape and double quotes in the path
    304         $has_double_quotes and $path =~ s/"/\\"/g;
    305         $path = "\"$path\"";
    306     }
    307     return $path;
    308 }
    309 
    310 sub do_command
    311 {
    312     my $cmd = shift;
    313     my $description = @_ ? shift : "command";
    314     my $die_on_fail = @_ ? shift : undef;
    315     $debug and print "% $cmd\n";
    316     system ($cmd);
    317     if ($? == -1)
    318     {
    319         $debug and printf ("error: %s failed to execute: $!\n", $description);
    320         $die_on_fail and $? and exit(1);
    321         return $?;
    322     }
    323     elsif ($? & 127)
    324     {
    325         $debug and printf("error: %s child died with signal %d, %s coredump\n",
    326                           $description,
    327                           ($? & 127),
    328                           ($? & 128) ? 'with' : 'without');
    329         $die_on_fail and $? and exit(1);
    330         return $?;
    331     }
    332     else
    333     {
    334         my $exit = $? >> 8;
    335         if ($exit)
    336         {
    337             $debug and printf("error: %s child exited with value %d\n", $description, $exit);
    338             $die_on_fail and exit(1);
    339         }
    340         return $exit;
    341     }
    342 }
    343 
    344 sub create_single_llvm_archive_for_arch
    345 {
    346     my $arch_dstroot = shift;
    347     my $split_into_objects = shift;
    348     my @object_dirs;
    349     my $object_dir;
    350     my $tmp_dir = $arch_dstroot;
    351     my $arch_output_file = "$arch_dstroot/$llvm_clang_basename";
    352     -e $arch_output_file and return;
    353     my $files = "$arch_dstroot/files.txt";
    354     open (FILES, ">$files") or die "Can't open $! for writing...\n";
    355 
    356     for my $path (@archive_files)
    357     {
    358         my $archive_fullpath = finalize_path ("$arch_dstroot/$path");
    359         if (-e $archive_fullpath)
    360         {
    361             if ($split_into_objects)
    362             {
    363                 my ($archive_file, $archive_dir, $archive_ext) = fileparse($archive_fullpath, ('.a'));
    364                 $object_dir = "$tmp_dir/$archive_file";
    365                 push @object_dirs, $object_dir;
    366 
    367                 do_command ("cd '$tmp_dir'; mkdir '$archive_file'; cd '$archive_file'; ar -x $archive_fullpath");
    368 
    369                 my @objects = bsd_glob("$object_dir/*.o");
    370                 foreach my $object (@objects)
    371                 {
    372                     my ($o_file, $o_dir) = fileparse($object);
    373                     my $new_object = "$object_dir/${archive_file}-$o_file";
    374                     print FILES "$new_object\n";
    375                     do_command ("mv '$object' '$new_object'");
    376                 }
    377             }
    378             else
    379             {
    380                 # just add the .a files into the file list
    381                 print FILES "$archive_fullpath\n";
    382             }
    383         }
    384         else
    385         {
    386             print "warning: archive doesn't exist: '$archive_fullpath'\n";
    387         }
    388     }
    389     close (FILES);
    390     do_command ("libtool -static -o '$arch_output_file' -filelist '$files'");
    391     do_command ("ranlib '$arch_output_file'");
    392 
    393     foreach $object_dir (@object_dirs)
    394     {
    395         do_command ("rm -rf '$object_dir'");
    396     }
    397     do_command ("rm -rf '$files'");
    398 }
    399 
    400 build_llvm();
    401