@@ -5,10 +5,15 @@ package main
5
5
//
6
6
7
7
import (
8
+ "errors"
9
+ "fmt"
8
10
"path/filepath"
11
+ "runtime"
9
12
10
13
"github.com/apex/log"
11
14
"github.com/ooni/probe-cli/v3/internal/cmd/buildtool/internal/buildtoolmodel"
15
+ "github.com/ooni/probe-cli/v3/internal/must"
16
+ "github.com/ooni/probe-cli/v3/internal/runtimex"
12
17
"github.com/ooni/probe-cli/v3/internal/shellx"
13
18
"github.com/spf13/cobra"
14
19
)
@@ -19,13 +24,26 @@ func iosSubcommand() *cobra.Command {
19
24
Use : "ios" ,
20
25
Short : "Builds oonimkall and its dependencies for iOS" ,
21
26
}
27
+
22
28
cmd .AddCommand (& cobra.Command {
23
29
Use : "gomobile" ,
24
30
Short : "Builds oonimkall for iOS using gomobile" ,
25
31
Run : func (cmd * cobra.Command , args []string ) {
26
32
iosBuildGomobile (& buildDeps {})
27
33
},
28
34
})
35
+
36
+ cmd .AddCommand (& cobra.Command {
37
+ Use : "cdeps [zlib|openssl|libevent|tor...]" ,
38
+ Short : "Cross compiles C dependencies for iOS" ,
39
+ Run : func (cmd * cobra.Command , args []string ) {
40
+ for _ , arg := range args {
41
+ iosCdepsBuildMain (arg , & buildDeps {})
42
+ }
43
+ },
44
+ Args : cobra .MinimumNArgs (1 ),
45
+ })
46
+
29
47
return cmd
30
48
}
31
49
@@ -41,6 +59,145 @@ func iosBuildGomobile(deps buildtoolmodel.Dependencies) {
41
59
output : filepath .Join ("MOBILE" , "ios" , "oonimkall.xcframework" ),
42
60
target : "ios" ,
43
61
}
62
+
44
63
log .Info ("building the mobile library using gomobile" )
45
64
gomobileBuild (config )
46
65
}
66
+
67
+ // iosCdepsBuildMain builds C dependencies for ios.
68
+ func iosCdepsBuildMain (name string , deps buildtoolmodel.Dependencies ) {
69
+ runtimex .Assert (runtime .GOOS == "darwin" , "this command requires darwin" )
70
+
71
+ // The ooni/probe-ios app explicitly only targets amd64 and arm64. It also targets
72
+ // as the minimum version iOS 12, while one cannot target a version of iOS > 10 when
73
+ // building for 32-bit targets. Hence, using only 64 bit archs here is fine.
74
+ archs := []string {"arm64" , "amd64" }
75
+ for _ , arch := range archs {
76
+ iosCdepsBuildArch (deps , arch , name )
77
+ }
78
+ }
79
+
80
+ // iosPlatformForOONIArch maps the ooniArch to the iOS platform
81
+ var iosPlatformForOONIArch = map [string ]string {
82
+ "amd64" : "iphonesimulator" ,
83
+ "arm64" : "iphoneos" ,
84
+ }
85
+
86
+ // iosAppleArchForOONIArch maps the ooniArch to the corresponding apple arch
87
+ var iosAppleArchForOONIArch = map [string ]string {
88
+ "amd64" : "x86_64" ,
89
+ "arm64" : "arm64" ,
90
+ }
91
+
92
+ // iosMinVersionFlagForOONIArch maps the ooniArch to the corresponding compiler flag
93
+ // to set the minimum version of either iphoneos or iphonesimulator.
94
+ //
95
+ // Note: the documentation of clang fetched on 2023-10-12 explicitly mentions that
96
+ // ios-version-min is an alias for iphoneos-version-min. Likewise, ios-simulator-version-min
97
+ // aliaes iphonesimulator-version-min.
98
+ //
99
+ // See https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mios-simulator-version-min
100
+ var iosMinVersionFlagForOONIArch = map [string ]string {
101
+ "amd64" : "-miphonesimulator-version-min=" ,
102
+ "arm64" : "-miphoneos-version-min=" ,
103
+ }
104
+
105
+ // iosCdepsBuildArch builds the given dependency for the given arch
106
+ func iosCdepsBuildArch (deps buildtoolmodel.Dependencies , ooniArch string , name string ) {
107
+ cdenv := iosNewCBuildEnv (deps , ooniArch )
108
+ switch name {
109
+ case "libevent" :
110
+ cdepsLibeventBuildMain (cdenv , deps )
111
+ case "openssl" :
112
+ cdepsOpenSSLBuildMain (cdenv , deps )
113
+ case "tor" :
114
+ cdepsTorBuildMain (cdenv , deps )
115
+ case "zlib" :
116
+ cdepsZlibBuildMain (cdenv , deps )
117
+ default :
118
+ panic (fmt .Errorf ("unknown dependency: %s" , name ))
119
+ }
120
+ }
121
+
122
+ // iosMinVersion is the minimum version that we support. We're using the
123
+ // same value used by the ooni/probe-ios app as of 2023-10.12.
124
+ const iosMinVersion = "12.0"
125
+
126
+ // iosNewCBuildEnv creates a new [cBuildEnv] for the given ooniArch ("arm64" or "amd64").
127
+ func iosNewCBuildEnv (deps buildtoolmodel.Dependencies , ooniArch string ) * cBuildEnv {
128
+ destdir := runtimex .Try1 (filepath .Abs (filepath .Join ( // must be absolute
129
+ "internal" , "libtor" , "ios" , ooniArch ,
130
+ )))
131
+
132
+ var (
133
+ appleArch = iosAppleArchForOONIArch [ooniArch ]
134
+ minVersionFlag = iosMinVersionFlagForOONIArch [ooniArch ]
135
+ platform = iosPlatformForOONIArch [ooniArch ]
136
+ )
137
+ runtimex .Assert (appleArch != "" , "empty appleArch" )
138
+ runtimex .Assert (minVersionFlag != "" , "empty minVersionFlag" )
139
+ runtimex .Assert (platform != "" , "empty platform" )
140
+
141
+ isysroot := deps .XCRun ("-sdk" , platform , "--show-sdk-path" )
142
+
143
+ out := & cBuildEnv {
144
+ ANDROID_HOME : "" , // not needed
145
+ ANDROID_NDK_ROOT : "" , // not needed
146
+ AS : deps .XCRun ("-find" , "-sdk" , platform , "as" ),
147
+ AR : deps .XCRun ("-find" , "-sdk" , platform , "ar" ),
148
+ BINPATH : "" , // not needed
149
+ CC : deps .XCRun ("-find" , "-sdk" , platform , "cc" ),
150
+ CFLAGS : []string {
151
+ "-isysroot" , isysroot ,
152
+ minVersionFlag + iosMinVersion , // tricky: they must be concatenated
153
+ "-O2" ,
154
+ "-arch" , appleArch ,
155
+ "-fembed-bitcode" ,
156
+ },
157
+ CONFIGURE_HOST : "" , // later
158
+ DESTDIR : destdir ,
159
+ CXX : deps .XCRun ("-find" , "-sdk" , platform , "c++" ),
160
+ CXXFLAGS : []string {
161
+ "-isysroot" , isysroot ,
162
+ minVersionFlag + iosMinVersion , // tricky: they must be concatenated
163
+ "-arch" , appleArch ,
164
+ "-fembed-bitcode" ,
165
+ "-O2" ,
166
+ },
167
+ GOARCH : ooniArch ,
168
+ GOARM : "" , // not needed
169
+ LD : deps .XCRun ("-find" , "-sdk" , platform , "ld" ),
170
+ LDFLAGS : []string {
171
+ "-isysroot" , isysroot ,
172
+ minVersionFlag + iosMinVersion , // tricky: they must be concatenated
173
+ "-arch" , appleArch ,
174
+ "-fembed-bitcode" ,
175
+ },
176
+ OPENSSL_COMPILER : "" , // later
177
+ OPENSSL_POST_COMPILER_FLAGS : []string {
178
+ minVersionFlag + iosMinVersion , // tricky: they must be concatenated
179
+ "-fembed-bitcode" ,
180
+ },
181
+ RANLIB : deps .XCRun ("-find" , "-sdk" , platform , "ranlib" ),
182
+ STRIP : deps .XCRun ("-find" , "-sdk" , platform , "strip" ),
183
+ }
184
+
185
+ switch ooniArch {
186
+ case "arm64" :
187
+ out .CONFIGURE_HOST = "arm-apple-darwin"
188
+ out .OPENSSL_COMPILER = "ios64-xcrun"
189
+ case "amd64" :
190
+ out .CONFIGURE_HOST = "x86_64-apple-darwin"
191
+ out .OPENSSL_COMPILER = "iossimulator-xcrun"
192
+ default :
193
+ panic (errors .New ("unsupported ooniArch" ))
194
+ }
195
+
196
+ return out
197
+ }
198
+
199
+ // iosXCRun invokes `xcrun [args]` and returns its result of panics. This function
200
+ // is called indirectly by the iOS build through [buildtoolmodel.Dependencies].
201
+ func iosXCRun (args ... string ) string {
202
+ return string (must .FirstLineBytes (must .RunOutput (log .Log , "xcrun" , args ... )))
203
+ }
0 commit comments