2019-03-07 06:42:41 +08:00
// To get started, run this tool with no args and read the help message.
//
// The build systems of musl-libc and glibc require specifying a single target
// architecture. Meanwhile, Zig supports out-of-the-box cross compilation for
// every target. So the process to create libc headers that Zig ships is to use
// this tool.
// First, use the musl/glibc build systems to create installations of all the
2019-03-12 22:28:05 +08:00
// targets in the `glibc_targets`/`musl_targets` variables.
2019-03-07 06:42:41 +08:00
// Next, run this tool to create a new directory which puts .h files into
// <arch> subdirectories, with `generic` being files that apply to all architectures.
// You'll then have to manually update Zig source repo with these new files.
const std = @import ( " std " ) ;
const builtin = @import ( " builtin " ) ;
const Arch = builtin . Arch ;
const Abi = builtin . Abi ;
const Os = builtin . Os ;
const assert = std . debug . assert ;
const LibCTarget = struct {
name : [ ] const u8 ,
2019-07-17 07:02:51 +08:00
arch : MultiArch ,
2019-03-07 06:42:41 +08:00
} ;
2019-07-17 07:02:51 +08:00
const MultiArch = union ( enum ) {
aarch64 ,
arm ,
mips ,
mips64 ,
powerpc64 ,
specific : @TagType ( Arch ) ,
fn eql ( a : MultiArch , b : MultiArch ) bool {
if ( @enumToInt ( a ) ! = @enumToInt ( b ) )
return false ;
if ( @TagType ( MultiArch ) ( a ) ! = . specific )
return true ;
return a . specific = = b . specific ;
}
} ;
const glibc_targets = [ _ ] LibCTarget {
2019-03-07 06:42:41 +08:00
LibCTarget {
. name = " aarch64_be-linux-gnu " ,
. zig_arch = Arch . aarch64_be ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " aarch64-linux-gnu " ,
. zig_arch = Arch . aarch64 ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " aarch64-linux-gnu-disable-multi-arch " ,
. zig_arch = Arch . aarch64 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " alpha-linux-gnu " ,
. zig_arch = null ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " armeb-linux-gnueabi " ,
. zig_arch = Arch . armeb ,
. zig_abi = Abi . gnueabi ,
} ,
LibCTarget {
. name = " armeb-linux-gnueabi-be8 " ,
. zig_arch = Arch . armeb ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " armeb-linux-gnueabihf " ,
. zig_arch = Arch . armeb ,
. zig_abi = Abi . gnueabihf ,
} ,
LibCTarget {
. name = " armeb-linux-gnueabihf-be8 " ,
. zig_arch = Arch . armeb ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " arm-linux-gnueabi " ,
. zig_arch = Arch . arm ,
. zig_abi = Abi . gnueabi ,
} ,
LibCTarget {
. name = " arm-linux-gnueabihf " ,
. zig_arch = Arch . arm ,
. zig_abi = Abi . gnueabihf ,
} ,
LibCTarget {
. name = " arm-linux-gnueabihf-v7a " ,
. zig_arch = Arch . arm ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " arm-linux-gnueabihf-v7a-disable-multi-arch " ,
. zig_arch = null ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " hppa-linux-gnu " ,
. zig_arch = null ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " i486-linux-gnu " ,
. zig_arch = null ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " i586-linux-gnu " ,
. zig_arch = null ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " i686-gnu " ,
. zig_arch = Arch . i386 ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " i686-linux-gnu " ,
. zig_arch = Arch . i386 ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " i686-linux-gnu-disable-multi-arch " ,
. zig_arch = null ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " i686-linux-gnu-enable-obsolete " ,
. zig_arch = Arch . i386 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " i686-linux-gnu-static-pie " ,
. zig_arch = Arch . i386 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " ia64-linux-gnu " ,
. zig_arch = null ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " m68k-linux-gnu " ,
. zig_arch = null ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " m68k-linux-gnu-coldfire " ,
. zig_arch = null ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " m68k-linux-gnu-coldfire-soft " ,
. zig_arch = null ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " microblazeel-linux-gnu " ,
. zig_arch = null ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " microblaze-linux-gnu " ,
. zig_arch = null ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips64el-linux-gnu-n32 " ,
. zig_arch = Arch . mips64el ,
. zig_abi = Abi . gnuabin32 ,
} ,
LibCTarget {
. name = " mips64el-linux-gnu-n32-nan2008 " ,
. zig_arch = Arch . mips64el ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips64el-linux-gnu-n32-nan2008-soft " ,
. zig_arch = Arch . mips64el ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips64el-linux-gnu-n32-soft " ,
. zig_arch = Arch . mips64el ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips64el-linux-gnu-n64 " ,
. zig_arch = Arch . mips64el ,
. zig_abi = Abi . gnuabi64 ,
} ,
LibCTarget {
. name = " mips64el-linux-gnu-n64-nan2008 " ,
. zig_arch = Arch . mips64el ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips64el-linux-gnu-n64-nan2008-soft " ,
. zig_arch = Arch . mips64el ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips64el-linux-gnu-n64-soft " ,
. zig_arch = Arch . mips64el ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips64-linux-gnu-n32 " ,
. zig_arch = Arch . mips64 ,
. zig_abi = Abi . gnuabin32 ,
} ,
LibCTarget {
. name = " mips64-linux-gnu-n32-nan2008 " ,
. zig_arch = Arch . mips64 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips64-linux-gnu-n32-nan2008-soft " ,
. zig_arch = Arch . mips64 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips64-linux-gnu-n32-soft " ,
. zig_arch = Arch . mips64 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips64-linux-gnu-n64 " ,
. zig_arch = Arch . mips64 ,
. zig_abi = Abi . gnuabi64 ,
} ,
LibCTarget {
. name = " mips64-linux-gnu-n64-nan2008 " ,
. zig_arch = Arch . mips64 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips64-linux-gnu-n64-nan2008-soft " ,
. zig_arch = Arch . mips64 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips64-linux-gnu-n64-soft " ,
. zig_arch = Arch . mips64 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mipsel-linux-gnu " ,
. zig_arch = Arch . mipsel ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " mipsel-linux-gnu-nan2008 " ,
. zig_arch = Arch . mipsel ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mipsel-linux-gnu-nan2008-soft " ,
. zig_arch = Arch . mipsel ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mipsel-linux-gnu-soft " ,
. zig_arch = Arch . mipsel ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips-linux-gnu " ,
. zig_arch = Arch . mips ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " mips-linux-gnu-nan2008 " ,
. zig_arch = Arch . mips ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips-linux-gnu-nan2008-soft " ,
. zig_arch = Arch . mips ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " mips-linux-gnu-soft " ,
. zig_arch = Arch . mips ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " powerpc64le-linux-gnu " ,
. zig_arch = Arch . powerpc64le ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " powerpc64-linux-gnu " ,
. zig_arch = Arch . powerpc64 ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " powerpc-linux-gnu " ,
. zig_arch = Arch . powerpc ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " powerpc-linux-gnu-power4 " ,
. zig_arch = Arch . powerpc ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " powerpc-linux-gnu-soft " ,
. zig_arch = Arch . powerpc ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " powerpc-linux-gnuspe " ,
. zig_arch = Arch . powerpc ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " powerpc-linux-gnuspe-e500v1 " ,
. zig_arch = Arch . powerpc ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " riscv64-linux-gnu-rv64imac-lp64 " ,
. zig_arch = Arch . riscv64 ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " riscv64-linux-gnu-rv64imafdc-lp64 " ,
. zig_arch = Arch . riscv64 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " riscv64-linux-gnu-rv64imafdc-lp64d " ,
. zig_arch = Arch . riscv64 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " s390-linux-gnu " ,
. zig_arch = null ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " s390x-linux-gnu " ,
. zig_arch = Arch . s390x ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " sh3eb-linux-gnu " ,
. zig_arch = null ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " sh3-linux-gnu " ,
. zig_arch = null ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " sh4eb-linux-gnu " ,
. zig_arch = null ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " sh4eb-linux-gnu-soft " ,
. zig_arch = null ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " sh4-linux-gnu " ,
. zig_arch = null ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " sh4-linux-gnu-soft " ,
. zig_arch = null ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " sparc64-linux-gnu " ,
. zig_arch = Arch . sparc ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " sparc64-linux-gnu-disable-multi-arch " ,
. zig_arch = Arch . sparc ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " sparcv9-linux-gnu " ,
. zig_arch = Arch . sparcv9 ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " sparcv9-linux-gnu-disable-multi-arch " ,
. zig_arch = Arch . sparcv9 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " x86_64-linux-gnu " ,
. zig_arch = Arch . x86_64 ,
. zig_abi = Abi . gnu ,
} ,
LibCTarget {
. name = " x86_64-linux-gnu-disable-multi-arch " ,
. zig_arch = Arch . x86_64 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " x86_64-linux-gnu-enable-obsolete " ,
. zig_arch = Arch . x86_64 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " x86_64-linux-gnu-static-pie " ,
. zig_arch = Arch . x86_64 ,
. zig_abi = null ,
} ,
LibCTarget {
. name = " x86_64-linux-gnu-x32 " ,
. zig_arch = Arch . x86_64 ,
. zig_abi = Abi . gnux32 ,
} ,
LibCTarget {
. name = " x86_64-linux-gnu-x32-static-pie " ,
. zig_arch = Arch . x86_64 ,
. zig_abi = null ,
} ,
} ;
2019-07-17 07:02:51 +08:00
const musl_targets = [ _ ] LibCTarget {
2019-03-12 22:28:05 +08:00
LibCTarget {
2019-07-17 07:02:51 +08:00
. name = " aarch64 " ,
. arch = MultiArch . aarch64 ,
2019-03-12 22:28:05 +08:00
} ,
LibCTarget {
2019-07-17 07:02:51 +08:00
. name = " arm " ,
. arch = MultiArch . arm ,
2019-03-12 22:28:05 +08:00
} ,
LibCTarget {
2019-07-17 07:02:51 +08:00
. name = " i386 " ,
. arch = MultiArch { . specific = . i386 } ,
2019-03-12 22:28:05 +08:00
} ,
LibCTarget {
2019-07-17 07:02:51 +08:00
. name = " mips " ,
. arch = MultiArch . mips ,
2019-03-12 22:28:05 +08:00
} ,
LibCTarget {
2019-07-17 07:02:51 +08:00
. name = " mips64 " ,
. arch = MultiArch . mips64 ,
2019-03-12 22:28:05 +08:00
} ,
LibCTarget {
2019-07-17 07:02:51 +08:00
. name = " powerpc " ,
. arch = MultiArch { . specific = . powerpc } ,
2019-03-12 22:28:05 +08:00
} ,
LibCTarget {
2019-07-17 07:02:51 +08:00
. name = " powerpc64 " ,
. arch = MultiArch . powerpc64 ,
2019-03-12 22:28:05 +08:00
} ,
LibCTarget {
2019-07-17 07:02:51 +08:00
. name = " riscv64 " ,
. arch = MultiArch { . specific = . riscv64 } ,
2019-03-12 22:28:05 +08:00
} ,
LibCTarget {
2019-07-17 07:02:51 +08:00
. name = " s390x " ,
. arch = MultiArch { . specific = . s390x } ,
2019-03-12 22:28:05 +08:00
} ,
LibCTarget {
2019-07-17 07:02:51 +08:00
. name = " x86_64 " ,
. arch = MultiArch { . specific = . x86_64 } ,
2019-03-12 22:28:05 +08:00
} ,
} ;
2019-03-07 06:42:41 +08:00
const DestTarget = struct {
2019-07-17 07:02:51 +08:00
arch : MultiArch ,
2019-03-07 06:42:41 +08:00
os : Os ,
abi : Abi ,
fn hash ( a : DestTarget ) u32 {
return @enumToInt ( a . arch ) + %
( @enumToInt ( a . os ) * % u32 ( 4202347608 ) ) + %
( @enumToInt ( a . abi ) * % u32 ( 4082223418 ) ) ;
}
fn eql ( a : DestTarget , b : DestTarget ) bool {
2019-07-17 07:02:51 +08:00
return a . arch . eql ( b . arch ) and
2019-03-07 06:42:41 +08:00
a . os = = b . os and
a . abi = = b . abi ;
}
} ;
const Contents = struct {
bytes : [ ] const u8 ,
hit_count : usize ,
hash : [ ] const u8 ,
is_generic : bool ,
fn hitCountLessThan ( lhs : * const Contents , rhs : * const Contents ) bool {
return lhs . hit_count < rhs . hit_count ;
}
} ;
2019-08-10 05:09:27 +08:00
comptime {
@compileError ( " the behavior of std.AutoHashMap changed and []const u8 will be treated as a pointer. will need to update the hash maps to actually do some kind of hashing on the slices. " ) ;
}
2019-03-07 06:42:41 +08:00
const HashToContents = std . AutoHashMap ( [ ] const u8 , Contents ) ;
const TargetToHash = std . HashMap ( DestTarget , [ ] const u8 , DestTarget . hash , DestTarget . eql ) ;
const PathTable = std . AutoHashMap ( [ ] const u8 , * TargetToHash ) ;
2019-07-17 07:02:51 +08:00
const LibCVendor = enum {
musl ,
glibc ,
} ;
2019-03-07 06:42:41 +08:00
pub fn main ( ) ! void {
2019-06-22 22:33:00 +08:00
var arena = std . heap . ArenaAllocator . init ( std . heap . direct_allocator ) ;
2019-03-07 06:42:41 +08:00
const allocator = & arena . allocator ;
2019-07-17 07:02:51 +08:00
const args = try std . process . argsAlloc ( allocator ) ;
2019-03-07 06:42:41 +08:00
var search_paths = std . ArrayList ( [ ] const u8 ) . init ( allocator ) ;
var opt_out_dir : ? [ ] const u8 = null ;
2019-03-12 22:28:05 +08:00
var opt_abi : ? [ ] const u8 = null ;
2019-03-07 06:42:41 +08:00
var arg_i : usize = 1 ;
while ( arg_i < args . len ) : ( arg_i + = 1 ) {
if ( std . mem . eql ( u8 , args [ arg_i ] , " --help " ) )
usageAndExit ( args [ 0 ] ) ;
if ( arg_i + 1 > = args . len ) {
std . debug . warn ( " expected argument after '{}' \n " , args [ arg_i ] ) ;
usageAndExit ( args [ 0 ] ) ;
}
if ( std . mem . eql ( u8 , args [ arg_i ] , " --search-path " ) ) {
try search_paths . append ( args [ arg_i + 1 ] ) ;
} else if ( std . mem . eql ( u8 , args [ arg_i ] , " --out " ) ) {
assert ( opt_out_dir = = null ) ;
opt_out_dir = args [ arg_i + 1 ] ;
2019-03-12 22:28:05 +08:00
} else if ( std . mem . eql ( u8 , args [ arg_i ] , " --abi " ) ) {
assert ( opt_abi = = null ) ;
opt_abi = args [ arg_i + 1 ] ;
2019-03-07 06:42:41 +08:00
} else {
std . debug . warn ( " unrecognized argument: {} \n " , args [ arg_i ] ) ;
usageAndExit ( args [ 0 ] ) ;
}
arg_i + = 1 ;
}
const out_dir = opt_out_dir orelse usageAndExit ( args [ 0 ] ) ;
2019-03-12 22:28:05 +08:00
const abi_name = opt_abi orelse usageAndExit ( args [ 0 ] ) ;
2019-07-17 07:02:51 +08:00
const vendor = if ( std . mem . eql ( u8 , abi_name , " musl " ) )
LibCVendor . musl
2019-03-12 22:28:05 +08:00
else if ( std . mem . eql ( u8 , abi_name , " glibc " ) )
2019-07-17 07:02:51 +08:00
LibCVendor . glibc
2019-03-12 22:28:05 +08:00
else {
std . debug . warn ( " unrecognized C ABI: {} \n " , abi_name ) ;
usageAndExit ( args [ 0 ] ) ;
} ;
2019-07-17 07:02:51 +08:00
const generic_name = try std . fmt . allocPrint ( allocator , " generic-{} " , abi_name ) ;
// TODO compiler crashed when I wrote this the canonical way
var libc_targets : [ ] const LibCTarget = undefined ;
switch ( vendor ) {
. musl = > libc_targets = musl_targets ,
. glibc = > @panic ( " TODO this regressed " ) , // glibc_targets,
}
2019-03-07 06:42:41 +08:00
var path_table = PathTable . init ( allocator ) ;
var hash_to_contents = HashToContents . init ( allocator ) ;
var max_bytes_saved : usize = 0 ;
var total_bytes : usize = 0 ;
var hasher = std . crypto . Sha256 . init ( ) ;
for ( libc_targets ) | libc_target | {
const dest_target = DestTarget {
2019-07-17 07:02:51 +08:00
. arch = libc_target . arch ,
. abi = switch ( vendor ) {
. musl = > . musl ,
else = > @panic ( " TODO this regressed " ) ,
} ,
. os = . linux ,
2019-03-07 06:42:41 +08:00
} ;
search : for ( search_paths . toSliceConst ( ) ) | search_path | {
2019-07-17 07:02:51 +08:00
var sub_path : [ ] const [ ] const u8 = undefined ;
switch ( vendor ) {
. musl = > {
sub_path = [ _ ] [ ] const u8 { search_path , libc_target . name , " usr " , " local " , " musl " , " include " } ;
} ,
. glibc = > {
sub_path = [ _ ] [ ] const u8 { search_path , libc_target . name , " usr " , " include " } ;
} ,
}
const target_include_dir = try std . fs . path . join ( allocator , sub_path ) ;
2019-03-07 06:42:41 +08:00
var dir_stack = std . ArrayList ( [ ] const u8 ) . init ( allocator ) ;
try dir_stack . append ( target_include_dir ) ;
while ( dir_stack . popOrNull ( ) ) | full_dir_name | {
2019-07-17 07:02:51 +08:00
var dir = std . fs . Dir . open ( allocator , full_dir_name ) catch | err | switch ( err ) {
2019-03-07 06:42:41 +08:00
error . FileNotFound = > continue : search ,
error . AccessDenied = > continue : search ,
else = > return err ,
} ;
defer dir . close ( ) ;
while ( try dir . next ( ) ) | entry | {
2019-07-17 07:02:51 +08:00
const full_path = try std . fs . path . join ( allocator , [ _ ] [ ] const u8 { full_dir_name , entry . name } ) ;
2019-03-07 06:42:41 +08:00
switch ( entry . kind ) {
2019-07-17 07:02:51 +08:00
. Directory = > try dir_stack . append ( full_path ) ,
. File = > {
const rel_path = try std . fs . path . relative ( allocator , target_include_dir , full_path ) ;
2019-03-07 06:42:41 +08:00
const raw_bytes = try std . io . readFileAlloc ( allocator , full_path ) ;
const trimmed = std . mem . trim ( u8 , raw_bytes , " \r \n \t " ) ;
total_bytes + = raw_bytes . len ;
const hash = try allocator . alloc ( u8 , 32 ) ;
hasher . reset ( ) ;
hasher . update ( rel_path ) ;
hasher . update ( trimmed ) ;
hasher . final ( hash ) ;
const gop = try hash_to_contents . getOrPut ( hash ) ;
if ( gop . found_existing ) {
max_bytes_saved + = raw_bytes . len ;
gop . kv . value . hit_count + = 1 ;
std . debug . warn (
2019-07-17 07:02:51 +08:00
" duplicate: {} {} ({Bi:2}) \n " ,
2019-03-07 06:42:41 +08:00
libc_target . name ,
rel_path ,
raw_bytes . len ,
) ;
} else {
gop . kv . value = Contents {
. bytes = trimmed ,
. hit_count = 1 ,
. hash = hash ,
. is_generic = false ,
} ;
}
const path_gop = try path_table . getOrPut ( rel_path ) ;
const target_to_hash = if ( path_gop . found_existing ) path_gop . kv . value else blk : {
const ptr = try allocator . create ( TargetToHash ) ;
ptr . * = TargetToHash . init ( allocator ) ;
path_gop . kv . value = ptr ;
break : blk ptr ;
} ;
assert ( ( try target_to_hash . put ( dest_target , hash ) ) = = null ) ;
} ,
else = > std . debug . warn ( " warning: weird file: {} \n " , full_path ) ,
}
}
}
break ;
} else {
std . debug . warn ( " warning: libc target not found: {} \n " , libc_target . name ) ;
}
}
2019-07-17 07:02:51 +08:00
std . debug . warn ( " summary: {Bi:2} could be reduced to {Bi:2} \n " , total_bytes , total_bytes - max_bytes_saved ) ;
try std . fs . makePath ( allocator , out_dir ) ;
2019-03-07 06:42:41 +08:00
var missed_opportunity_bytes : usize = 0 ;
// iterate path_table. for each path, put all the hashes into a list. sort by hit_count.
// the hash with the highest hit_count gets to be the "generic" one. everybody else
// gets their header in a separate arch directory.
var path_it = path_table . iterator ( ) ;
while ( path_it . next ( ) ) | path_kv | {
var contents_list = std . ArrayList ( * Contents ) . init ( allocator ) ;
{
var hash_it = path_kv . value . iterator ( ) ;
while ( hash_it . next ( ) ) | hash_kv | {
const contents = & hash_to_contents . get ( hash_kv . value ) . ? . value ;
try contents_list . append ( contents ) ;
}
}
std . sort . sort ( * Contents , contents_list . toSlice ( ) , Contents . hitCountLessThan ) ;
var best_contents = contents_list . popOrNull ( ) . ? ;
if ( best_contents . hit_count > 1 ) {
// worth it to make it generic
2019-07-17 07:02:51 +08:00
const full_path = try std . fs . path . join ( allocator , [ _ ] [ ] const u8 { out_dir , generic_name , path_kv . key } ) ;
try std . fs . makePath ( allocator , std . fs . path . dirname ( full_path ) . ? ) ;
2019-03-07 06:42:41 +08:00
try std . io . writeFile ( full_path , best_contents . bytes ) ;
best_contents . is_generic = true ;
while ( contents_list . popOrNull ( ) ) | contender | {
if ( contender . hit_count > 1 ) {
const this_missed_bytes = contender . hit_count * contender . bytes . len ;
missed_opportunity_bytes + = this_missed_bytes ;
2019-07-17 07:02:51 +08:00
std . debug . warn ( " Missed opportunity ({Bi:2}): {} \n " , this_missed_bytes , path_kv . key ) ;
2019-03-07 06:42:41 +08:00
} else break ;
}
}
var hash_it = path_kv . value . iterator ( ) ;
while ( hash_it . next ( ) ) | hash_kv | {
const contents = & hash_to_contents . get ( hash_kv . value ) . ? . value ;
if ( contents . is_generic ) continue ;
const dest_target = hash_kv . key ;
2019-07-17 07:02:51 +08:00
const arch_name = switch ( dest_target . arch ) {
. specific = > | a | @tagName ( a ) ,
else = > @tagName ( dest_target . arch ) ,
} ;
2019-03-07 06:42:41 +08:00
const out_subpath = try std . fmt . allocPrint (
allocator ,
" {}-{}-{} " ,
2019-07-17 07:02:51 +08:00
arch_name ,
2019-03-07 06:42:41 +08:00
@tagName ( dest_target . os ) ,
@tagName ( dest_target . abi ) ,
) ;
2019-07-17 07:02:51 +08:00
const full_path = try std . fs . path . join ( allocator , [ _ ] [ ] const u8 { out_dir , out_subpath , path_kv . key } ) ;
try std . fs . makePath ( allocator , std . fs . path . dirname ( full_path ) . ? ) ;
2019-03-07 06:42:41 +08:00
try std . io . writeFile ( full_path , contents . bytes ) ;
}
}
}
fn usageAndExit ( arg0 : [ ] const u8 ) noreturn {
2019-03-12 22:28:05 +08:00
std . debug . warn ( " Usage: {} [--search-path <dir>] --out <dir> --abi <name> \n " , arg0 ) ;
2019-03-07 06:42:41 +08:00
std . debug . warn ( " --search-path can be used any number of times. \n " ) ;
std . debug . warn ( " subdirectories of search paths look like, e.g. x86_64-linux-gnu \n " ) ;
std . debug . warn ( " --out is a dir that will be created, and populated with the results \n " ) ;
2019-03-12 22:28:05 +08:00
std . debug . warn ( " --abi is either musl or glibc \n " ) ;
2019-07-17 07:02:51 +08:00
std . process . exit ( 1 ) ;
2019-03-07 06:42:41 +08:00
}