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 11use strict; 12use File::Basename; 13use File::Glob ':glob'; 14use List::Util qw[min max]; 15 16our $llvm_srcroot = $ENV{SCRIPT_INPUT_FILE_0}; 17our $llvm_dstroot = $ENV{SCRIPT_INPUT_FILE_1}; 18 19our $llvm_clang_outfile = $ENV{SCRIPT_OUTPUT_FILE_0}; 20our ($llvm_clang_basename, $llvm_clang_dirname) = fileparse ($llvm_clang_outfile); 21 22our $llvm_configuration = $ENV{LLVM_CONFIGURATION}; 23 24our $llvm_revision = "HEAD"; 25our $clang_revision = "HEAD"; 26 27our $SRCROOT = "$ENV{SRCROOT}"; 28our @archs = split (/\s+/, $ENV{ARCHS}); 29my $os_release = 11; 30 31my $original_env_path = $ENV{PATH}; 32 33our %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 41our $llvm_config_href = undef; 42if (exists $llvm_config_info{"$llvm_configuration"}) 43{ 44 $llvm_config_href = $llvm_config_info{$llvm_configuration}; 45} 46else 47{ 48 die "Unsupported LLVM configuration: '$llvm_configuration'\n"; 49} 50 51our @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 107if (-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} 112else 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. 134if (-e $llvm_clang_outfile) 135{ 136 exit 0; 137} 138 139 140# Get our options 141 142our $debug = 1; 143 144sub 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 154sub 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#---------------------------------------------------------------------- 290sub 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 310sub 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 344sub 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 400build_llvm(); 401