44
44
45
45
#![ deny( missing_docs) ]
46
46
47
+ #[ macro_use]
48
+ extern crate lazy_static;
49
+
47
50
extern crate cc;
51
+ extern crate regex;
48
52
53
+ use regex:: Regex ;
49
54
use std:: env;
50
55
use std:: ffi:: { OsStr , OsString } ;
51
56
use std:: fs:: { self , File } ;
@@ -854,6 +859,8 @@ trait Target {
854
859
855
860
fn get_target ( target_triple : & str ) -> Box < dyn Target > {
856
861
let target: Option < Box < dyn Target > > ;
862
+ target = AppleTarget :: new ( target_triple)
863
+ . map ( |apple_target| Box :: new ( apple_target) as Box < dyn Target > ) ;
857
864
target. unwrap_or_else ( || Box :: new ( GenericTarget :: new ( target_triple) ) )
858
865
}
859
866
@@ -867,6 +874,177 @@ impl GenericTarget {
867
874
868
875
impl Target for GenericTarget { }
869
876
877
+ struct AppleTarget {
878
+ rust_target : String ,
879
+ rust_target_arch : String ,
880
+ rust_target_platform : String ,
881
+ }
882
+
883
+ impl AppleTarget {
884
+ fn new ( target_triple : & str ) -> Option < AppleTarget > {
885
+ let parts: Vec < & str > = target_triple. split ( '-' ) . collect ( ) ;
886
+ if parts. len ( ) < 3 {
887
+ return None ;
888
+ }
889
+
890
+ let rust_target_arch = parts[ 0 ] ;
891
+ let rust_target_vendor = parts[ 1 ] ;
892
+ let rust_target_platform = parts[ 2 ] ;
893
+
894
+ if rust_target_vendor != "apple" {
895
+ return None ;
896
+ }
897
+ if rust_target_platform != "ios" && rust_target_platform != "darwin" {
898
+ eprintln ! (
899
+ "Warning: unknown Apple platform ({}) for target: {}" ,
900
+ rust_target_platform, target_triple
901
+ ) ;
902
+ return None ;
903
+ }
904
+
905
+ Some ( AppleTarget {
906
+ rust_target : target_triple. to_owned ( ) ,
907
+ rust_target_arch : rust_target_arch. to_owned ( ) ,
908
+ rust_target_platform : rust_target_platform. to_owned ( ) ,
909
+ } )
910
+ }
911
+
912
+ fn is_ios_target ( & self ) -> bool {
913
+ self . rust_target_platform == "ios"
914
+ }
915
+
916
+ fn is_osx_target ( & self ) -> bool {
917
+ self . rust_target_platform == "darwin"
918
+ }
919
+
920
+ fn cmake_target_arch ( & self ) -> Option < String > {
921
+ match self . rust_target_arch . as_str ( ) {
922
+ "aarch64" => Some ( "arm64" . to_owned ( ) ) ,
923
+ "armv7" => Some ( "armv7" . to_owned ( ) ) ,
924
+ "armv7s" => Some ( "armv7s" . to_owned ( ) ) ,
925
+ "i386" => Some ( "i386" . to_owned ( ) ) ,
926
+ "x86_64" => Some ( "x86_64" . to_owned ( ) ) ,
927
+ _ => {
928
+ eprintln ! (
929
+ "Warning: unknown architecture for target: {}" ,
930
+ self . rust_target_arch
931
+ ) ;
932
+ None
933
+ }
934
+ }
935
+ }
936
+
937
+ fn sdk_name ( & self ) -> Option < String > {
938
+ if self . is_ios_target ( ) {
939
+ match self . rust_target_arch . as_str ( ) {
940
+ "aarch64" | "armv7" | "armv7s" => Some ( "iphoneos" . to_owned ( ) ) ,
941
+ "i386" | "x86_64" => Some ( "iphonesimulator" . to_owned ( ) ) ,
942
+ _ => {
943
+ eprintln ! (
944
+ "Warning: unknown architecture for Apple target: {}" ,
945
+ self . rust_target_arch
946
+ ) ;
947
+ None
948
+ }
949
+ }
950
+ } else if self . is_osx_target ( ) {
951
+ Some ( "macosx" . to_owned ( ) )
952
+ } else {
953
+ eprintln ! (
954
+ "Warning: could not determine sdk name for Apple target: {}" ,
955
+ self . rust_target
956
+ ) ;
957
+ None
958
+ }
959
+ }
960
+
961
+ fn deployment_target ( & self ) -> Option < String > {
962
+ if self . is_ios_target ( ) {
963
+ println ! ( "cargo:rerun-if-env-changed=IPHONEOS_DEPLOYMENT_TARGET" ) ;
964
+ Some ( std:: env:: var ( "IPHONEOS_DEPLOYMENT_TARGET" ) . unwrap_or_else ( |_| "7.0" . into ( ) ) )
965
+ } else if self . is_osx_target ( ) {
966
+ println ! ( "cargo:rerun-if-env-changed=MACOSX_DEPLOYMENT_TARGET" ) ;
967
+ Some ( std:: env:: var ( "MACOSX_DEPLOYMENT_TARGET" ) . unwrap_or_else ( |_| "" . into ( ) ) )
968
+ } else {
969
+ eprintln ! (
970
+ "Warning: could not determine deployment target for Apple target: {}" ,
971
+ self . rust_target
972
+ ) ;
973
+ None
974
+ }
975
+ }
976
+ }
977
+
978
+ impl Target for AppleTarget {
979
+ fn add_cmake_defines ( & self , cmd : & mut Command , config : & Config ) {
980
+ // These 3 CMAKE_OSX_* variables apply to all Apple platforms
981
+
982
+ if !config. defined ( "CMAKE_OSX_ARCHITECTURES" ) {
983
+ if let Some ( cmake_target_arch) = self . cmake_target_arch ( ) {
984
+ cmd. arg ( format ! ( "-DCMAKE_OSX_ARCHITECTURES={}" , cmake_target_arch) ) ;
985
+ }
986
+ }
987
+
988
+ if !config. defined ( "CMAKE_OSX_SYSROOT" ) {
989
+ if let Some ( sdk_name) = self . sdk_name ( ) {
990
+ cmd. arg ( format ! ( "-DCMAKE_OSX_SYSROOT={}" , sdk_name) ) ;
991
+ }
992
+ }
993
+
994
+ if !config. defined ( "CMAKE_OSX_DEPLOYMENT_TARGET" ) {
995
+ if let Some ( deployment_target) = self . deployment_target ( ) {
996
+ cmd. arg ( format ! (
997
+ "-DCMAKE_OSX_DEPLOYMENT_TARGET={}" ,
998
+ deployment_target
999
+ ) ) ;
1000
+ }
1001
+ }
1002
+
1003
+ // CMAKE_SYSTEM_NAME is used to tell cmake we're cross-compiling
1004
+ if self . is_ios_target ( ) && !config. defined ( "CMAKE_SYSTEM_NAME" ) {
1005
+ cmd. arg ( "-DCMAKE_SYSTEM_NAME=iOS" ) ;
1006
+ }
1007
+ }
1008
+
1009
+ fn should_exclude_env_var ( & self , key : & OsStr , _value : & OsStr ) -> bool {
1010
+ key. to_str ( ) . map_or ( false , |key| {
1011
+ // These cause issues with llvm if an env var for a different Apple platform
1012
+ // is present. Since cmake handles communicating these values to llvm, and
1013
+ // we use cmake defines to tell cmake what the value is, the env vars themselves
1014
+ // are filtered out.
1015
+ key. ends_with ( "DEPLOYMENT_TARGET" ) || key. starts_with ( "SDK" )
1016
+ } )
1017
+ }
1018
+
1019
+ fn filter_compiler_args ( & self , flags : & mut OsString ) {
1020
+ if let Some ( flags_str) = flags. to_str ( ) {
1021
+ lazy_static ! {
1022
+ static ref ARCH_REGEX : Regex = Regex :: new( "-arch [^ ]+ " ) . unwrap( ) ;
1023
+ static ref DEPLOYMENT_TARGET_REGEX : Regex =
1024
+ Regex :: new( "-m[\\ w-]+-version-min=[\\ d.]+ " ) . unwrap( ) ;
1025
+ static ref SYSROOT_REGEX : Regex = Regex :: new( "-isysroot [^ ]+ " ) . unwrap( ) ;
1026
+ }
1027
+
1028
+ let mut flags_string = flags_str. to_owned ( ) ;
1029
+ flags_string. push ( ' ' ) ;
1030
+
1031
+ // These are set by cmake
1032
+ flags_string = ARCH_REGEX . replace ( & flags_string, "" ) . into_owned ( ) ;
1033
+ flags_string = DEPLOYMENT_TARGET_REGEX
1034
+ . replace ( & flags_string, "" )
1035
+ . into_owned ( ) ;
1036
+ flags_string = SYSROOT_REGEX . replace ( & flags_string, "" ) . into_owned ( ) ;
1037
+
1038
+ if flags_string. ends_with ( ' ' ) {
1039
+ flags_string. pop ( ) ;
1040
+ }
1041
+
1042
+ flags. clear ( ) ;
1043
+ flags. push ( OsString :: from ( flags_string) ) ;
1044
+ }
1045
+ }
1046
+ }
1047
+
870
1048
fn run ( cmd : & mut Command , program : & str ) {
871
1049
println ! ( "running: {:?}" , cmd) ;
872
1050
let status = match cmd. status ( ) {
0 commit comments