diff --git a/.gitignore b/.gitignore index a0a0e17d..c3ce0740 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /Build /Install +/Temp diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..45906546 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,93 @@ +AllCops: + Exclude: + - Build/**/* + - Install/**/* + - Projects/**/* + - Sources/**/* + +Metrics/AbcSize: + Max: 50 + +Metrics/ClassLength: + Max: 240 + +Metrics/MethodLength: + Max: 80 + +Metrics/CyclomaticComplexity: + Max: 20 + +Metrics/PerceivedComplexity: + Max: 20 + +Style/IfUnlessModifier: + Enabled: false + +Style/SpecialGlobalVars: + Enabled: false + +Style/BracesAroundHashParameters: + Enabled: false + +Style/WordArray: + EnforcedStyle: brackets + +Style/Documentation: + Enabled: false + +Style/AsciiComments: + Enabled: false + +Style/SymbolArray: + Enabled: false + +Style/RedundantReturn: + Enabled: false + +Style/MethodCallWithoutArgsParentheses: + Enabled: false + +Style/GuardClause: + Enabled: false + +Style/BlockDelimiters: + Enabled: false + +Style/NegatedIf: + Enabled: false + +Style/DefWithParentheses: + Enabled: false + +Style/StringLiterals: + Enabled: false + +Layout/EmptyLinesAroundClassBody: + EnforcedStyle: empty_lines + +Layout/IndentationWidth: + Width: 3 + +Naming/VariableName: + EnforcedStyle: camelCase + +Naming/MethodName: + Enabled: false + +Style/InverseMethods: + Enabled: false + +Layout/EmptyLinesAroundBlockBody: + Enabled: false + +Naming/UncommunicativeMethodParamName: + Enabled: false + +Naming/UncommunicativeBlockParamName: + Enabled: false + +Layout/EmptyLinesAroundModuleBody: + Enabled: false + +Metrics/LineLength: + Enabled: false diff --git a/Downloads/.gitignore b/Downloads/.gitignore new file mode 100644 index 00000000..6ec84a6b --- /dev/null +++ b/Downloads/.gitignore @@ -0,0 +1,4 @@ +/*/ +/*.zip +/*.tgz +/*.tar.gz diff --git a/Downloads/Readme.md b/Downloads/Readme.md new file mode 100644 index 00000000..e8fd802d --- /dev/null +++ b/Downloads/Readme.md @@ -0,0 +1 @@ +# Automatically or Manually downloadded Android NDK archive will be placed here diff --git a/Patches/swift-corelibs-foundation/MissedLocaleHeaders.patch b/Patches/swift-corelibs-foundation/MissedLocaleHeaders.patch new file mode 100644 index 00000000..211efd38 --- /dev/null +++ b/Patches/swift-corelibs-foundation/MissedLocaleHeaders.patch @@ -0,0 +1,14 @@ +diff --git a/build.py b/build.py +index 8ee475f374dbb2cf479d7447c953719643bf8075..b228a4dcc6fd4c04619e03d22ff32bbd93d076e9 100755 +--- a/build.py ++++ b/build.py +@@ -211,6 +211,9 @@ private = [ + 'CoreFoundation/PlugIn.subproj/CFBundle_BinaryTypes.h', + 'CoreFoundation/Locale.subproj/CFICULogging.h', + 'CoreFoundation/Locale.subproj/CFLocaleInternal.h', ++ 'CoreFoundation/Locale.subproj/CFCalendar_Internal.h', ++ 'CoreFoundation/Locale.subproj/CFDateComponents.h', ++ 'CoreFoundation/Locale.subproj/CFDateInterval.h', + 'CoreFoundation/StringEncodings.subproj/CFUnicodePrecomposition.h', + 'CoreFoundation/Base.subproj/CFPriv.h', + 'CoreFoundation/StringEncodings.subproj/CFUniCharPriv.h', diff --git a/Patches/swift-corelibs-foundation/Readme.txt b/Patches/swift-corelibs-foundation/Readme.txt new file mode 100644 index 00000000..3cf5f5f2 --- /dev/null +++ b/Patches/swift-corelibs-foundation/Readme.txt @@ -0,0 +1 @@ +Bugreport: https://bugs.swift.org/browse/SR-9513 \ No newline at end of file diff --git a/Patches/swift-corelibs-libdispatch/CmakeSystemProcessor.patch b/Patches/swift-corelibs-libdispatch/CmakeSystemProcessor.patch new file mode 100644 index 00000000..e0ea67be --- /dev/null +++ b/Patches/swift-corelibs-libdispatch/CmakeSystemProcessor.patch @@ -0,0 +1,13 @@ +diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake +index 60f8b45a33e1546dce4aa2b30d3f9070f7b37ab9..14b4e950210f72321f1418531687ad67fc44e7a2 100644 +--- a/cmake/modules/SwiftSupport.cmake ++++ b/cmake/modules/SwiftSupport.cmake +@@ -228,6 +228,8 @@ function(get_swift_host_arch result_var_name) + set("${result_var_name}" "s390x" PARENT_SCOPE) + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv6l") + set("${result_var_name}" "armv6" PARENT_SCOPE) ++ elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7-a") ++ set("${result_var_name}" "armv7" PARENT_SCOPE) + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7l") + set("${result_var_name}" "armv7" PARENT_SCOPE) + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64") diff --git a/Projects/Hello/hello.swift b/Projects/Hello/hello.swift index 24e44609..8ff93f57 100755 --- a/Projects/Hello/hello.swift +++ b/Projects/Hello/hello.swift @@ -2,3 +2,66 @@ // Project which uses Dispatch and Foundation frameworks will be added as soon, // as Workflow will support Dispatch and Foundation frameworks compilation. print("Hello, This Is Swift!") + +/* +import Foundation +import Dispatch + + +let op = BlockOperation { + print("Operation") +} +let opQueue = OperationQueue() +opQueue.addOperations([op], waitUntilFinished: true) + +let sema = DispatchSemaphore(value: 0) + +let queue = DispatchQueue(label: "queueName") +queue.async { + print("XYZ") + sema.signal() +} + +if sema.wait(timeout: .now() + 10) == .timedOut { + print("~~~~~~") +} + +let config = URLSessionConfiguration() +let session = URLSession(configuration: config) +if let url = URL(string: "https://www.example.com") { + let sema2 = DispatchSemaphore(value: 0) + let task = session.dataTask(with: url) { data, response, error in + if let response = response { + print(response) + } + if let error = error { + print(error) + } + if let data = data { + print(data) + } + sema2.signal() + } + print(task) + task.resume() + if sema2.wait(timeout: .now() + 10) == .timedOut { + print("~~~~~~") + } +} else { + print("bad url") +} + +let json = ["name": "Sveta"] +do { + let data = try JSONSerialization.data(withJSONObject: json, options: []) + struct Person: Decodable { + let name: String + } + + let person = try JSONDecoder().decode(Person.self, from: data) + print(person.name) + +} catch { + print(error) +} +*/ diff --git a/Rakefile b/Rakefile index 34db9cae..443a7ee0 100755 --- a/Rakefile +++ b/Rakefile @@ -3,7 +3,16 @@ require_relative "Scripts/Builders/ICUBuilder.rb" require_relative "Scripts/Builders/AndroidBuilder.rb" require_relative "Scripts/Builders/SwiftBuilder.rb" -require_relative "Scripts/HelloProjectBuilder.rb" +require_relative "Scripts/Builders/FoundationBuilder.rb" +require_relative "Scripts/Builders/DispatchBuilder.rb" +require_relative "Scripts/Builders/CurlBuilder.rb" +require_relative "Scripts/Builders/OpenSSLBuilder.rb" +require_relative "Scripts/Builders/XMLBuilder.rb" +require_relative "Scripts/Builders/HelloProjectBuilder.rb" +require_relative "Scripts/Builders/LLVMBuilder.rb" +require_relative "Scripts/Builders/CMarkBuilder.rb" +require_relative "Scripts/Builders/ClangBuilder.rb" +require_relative "Scripts/Builders/CompilerRTBuilder.rb" require_relative "Scripts/ADBHelper.rb" # References: @@ -11,165 +20,274 @@ require_relative "Scripts/ADBHelper.rb" # - Using Rake to Automate Tasks: https://www.stuartellis.name/articles/rake/ # -task default: %w[usage] +task default: ['usage'] task :usage do help = < [:linux, :armv7a, :x86, :aarch64] do - puts "Done!" - end + desc "Setup NDK Toolchain." + task :setup do + AndroidBuilder.new(Arch.armv7a).setup + end - desc "Builds ICU for Linux" - task :linux do - ICUBuilder.new("linux").make - end + desc "Build Swift Toolchain." + task build: ["develop:armv7a:make:icu", "develop:armv7a:make:swift"] do + end - desc "Builds ICU for armv7a" - task :armv7a do - ICUBuilder.new("armv7a").make - end + namespace :project do - desc "Builds ICU for x86" - task :x86 do - ICUBuilder.new("x86").make + desc "Builds Sample project" + task :build do + HelloProjectBuilder.new(Arch.armv7a).build end - desc "Builds ICU for aarch64" - task :aarch64 do - ICUBuilder.new("aarch64").make + desc "Deploy and Run on Android" + task deploy: ["develop:armv7a:install:project", "develop:armv7a:run:project"] do end end + end -namespace :ndk do - desc "Cleans NDK build." - task :clean do - AndroidBuilder.new("").clean - end +namespace :develop do + + namespace :armv7a do + + namespace :configure do + desc "Configure ICU" + task :icu do + ICUBuilder.new(Arch.armv7a).configure + end + desc "Configure Swift" + task :swift do + SwiftBuilder.new(Arch.armv7a).configure + end + desc "Configure LLVM" + task :llvm do + LLVMBuilder.new(Arch.armv7a).configure + end + desc "Configure CMark" + task :cmark do + CMarkBuilder.new(Arch.armv7a).configure + end + end - desc "Setup Android toolchains for All platforms." - task :setup do - AndroidBuilder.new("armv7a").setupToolchain - AndroidBuilder.new("x86").setupToolchain - AndroidBuilder.new("aarch64").setupToolchain - end -end + namespace :build do + desc "Build ICU" + task :icu do + ICUBuilder.new(Arch.armv7a).build + end + desc "Build Swift" + task :swift do + SwiftBuilder.new(Arch.armv7a).build + end + desc "Build LLVM" + task :llvm do + LLVMBuilder.new(Arch.armv7a).build + end + desc "Build CMark" + task :cmark do + CMarkBuilder.new(Arch.armv7a).build + end + end -namespace :swift do + namespace :install do + desc "Install ICU" + task :icu do + ICUBuilder.new(Arch.armv7a).install + end + desc "Install Swift" + task :swift do + SwiftBuilder.new(Arch.armv7a).install + end + desc "Install LLVM" + task :llvm do + LLVMBuilder.new(Arch.armv7a).install + end + desc "Install CMark" + task :cmark do + CMarkBuilder.new(Arch.armv7a).install + end + + desc "Install Hello project on Android" + task :project do + binary = HelloProjectBuilder.new(Arch.armv7a).executable + helper = ADBHelper.new() + helper.deployLibs + helper.deployProducts([binary]) + end + end - desc "Builds Swift for Android" - task :build do - SwiftBuilder.new().make - end + namespace :make do + desc "Configure, Build and Install ICU" + task :icu do + ICUBuilder.new(Arch.armv7a).make + end + desc "Configure, Build and Install Swift" + task :swift do + SwiftBuilder.new(Arch.armv7a).make + end + desc "Configure, Build and Install LLVM" + task :llvm do + LLVMBuilder.new(Arch.armv7a).make + end + desc "Configure, Build and Install CMark" + task :cmark do + CMarkBuilder.new(Arch.armv7a).make + end + desc "Configure, Build and Install libDispatch" + task :dispatch do + DispatchBuilder.new().make + end + desc "Configure, Build and Install libFoundation" + task :foundation do + FoundationBuilder.new().make + end + end - desc "Swift: Show Build options (i.e. `swift/utils/build-script --help`)" - task :help do - SwiftBuilder.new().help - end + namespace :clean do + desc "Clean ICU." + task :icu do + ICUBuilder.new(Arch.armv7a).clean + end + + desc "Clean NDK." + task :ndk do + AndroidBuilder.new(Arch.armv7a).clean + end + + desc "Clean Swift." + task :swift do + SwiftBuilder.new(Arch.armv7a).clean + end + + desc "Clean LLVM." + task :llvm do + LLVMBuilder.new(Arch.armv7a).clean + end + + desc "Clean libDispatch" + task :dispatch do + DispatchBuilder.new().clean + end + + desc "Clean libFoundation" + task :foundation do + FoundationBuilder.new().clean + end + + desc "Clean Hello project." + task :project do + ADBHelper.new().cleanup(HelloProjectBuilder.new(Arch.armv7a).executableName) + end + end - desc "Swift: Update sources (i.e. `swift/utils/update-checkout`)" - task :update do - SwiftBuilder.new().update - end + namespace :run do + desc "Run Hello project on Android" + task :project do + ADBHelper.new().run(HelloProjectBuilder.new(Arch.armv7a).executableName) + end + end -end + namespace :xml do -namespace :project do + desc "Checkout libXML" + task :checkout do + XMLBuilder.new().checkout + end - namespace :hello do + desc "Build libXML" + task :make do + XMLBuilder.new().make + end - desc "Project Hello: Build" - task :build do - HelloProjectBuilder.new().make end - desc "Project Hello: Verify" - task :verify do - ADBHelper.new().verify - end + namespace :curl do - desc "Project Hello: Install on Android" - task :install do - binary = "#{Config.buildRoot}/hello/hello" - helper = ADBHelper.new() - helper.deployLibs - helper.deployProducts([binary]) - end + desc "Checkout curl" + task :checkout do + CurlBuilder.new().checkout + end - desc "Project Hello: Run on Android" - task :run do - ADBHelper.new().run("hello") - end + desc "Build curl" + task :make do + CurlBuilder.new().make + end - desc "Project Hello: Cleanup on Android" - task :cleanup do - ADBHelper.new().cleanup("hello") end - desc "Project Hello: Deploy and Run on Android" - task :deploy => [:install, :run] do + namespace :openssl do + + desc "Checkout OpenSSL" + task :checkout do + OpenSSLBuilder.new().checkout + end + + desc "Make OpenSSL" + task :make do + OpenSSLBuilder.new().make + end end end - end diff --git a/Readme.md b/Readme.md index a8786abf..fe4e862e 100644 --- a/Readme.md +++ b/Readme.md @@ -1,13 +1,8 @@ -I. Prerequesites -================ +Setup and Build +=============== **Note**: Every time you see `host$` – this means that command should be executed on **HOST** macOS computer. Every time you see `box$` – this means that command should be executed on virtual **GUEST** Linux OS. -**Note**: If you found mistake or something from written below is not working, then open issue and specify exact step which fails. I.e. `Step B.1.ii`. - -A. Initial setup ----------------- - 1. Download and install software. - Vagrant: https://www.vagrantup.com @@ -21,226 +16,60 @@ A. Initial setup host$ vagrant --version ``` -3. Clone this repository. - - ```bash - host$ git clone https://github.com/vgorloff/Android-On-Swift.git - host$ cd Android-On-Swift - ``` - -B. Setting up Ubuntu box ------------------------- - -**Note**: Most of the steps similar to [Getting Started](https://www.vagrantup.com/intro/getting-started/index.html) from Vagrant website. - -1. Setup Ubuntu box. - - 1. Download Ubuntu box image. - - **Note**: Usually you need to download box image once. - - ```bash - host$ vagrant box add ubuntu/bionic64 - ``` - - **Note**: You can explore trending boxes here: - - - https://app.vagrantup.com/boxes/search - - https://app.vagrantup.com/ubuntu/boxes/bionic64 - - 2. (Optionall) Verify downloaded Ubuntu image in local folder. - - ```bash - host$ ls -l ~/.vagrant.d/boxes - ``` - - 3. Start box and connect via SSH. - - ```bash - host$ vagrant up - host$ vagrant ssh - ``` - - **Note**: Box will be created in directory specified in VirtualBox settings. Detalis in [this post](http://www.thisprogrammingthing.com/2013/changing-the-directory-vagrant-stores-the-vms-in/). - - 4. (Optionall) Verify Ubuntu version. - - ```bash - box$ lsb_release -irc - ``` - - 5. (Optionall) Explore synced folders: - - ```bash - box$ ls -l /vagrant - ``` - - **Note**: You should see this `Readme.md` file inside Ubuntu Box. - - As result we have Ubuntu box running on macOS. - -2. Review Box settings. - - Since we going to compile Swift. It is a good idea to review box's Memory and CPU settings to avoid situations like below. - - ``` - /usr/bin/ld.gold: out of memory - clang: error: linker command failed with exit code 1 (use -v to see invocation) - ``` - - ``` - LLVM ERROR: out of memory - ``` - - 1. Shutdown box. - - ```bash - host$ vagrant halt - ``` +3. Download Ubuntu image. - 2. Review and update Vagrantfile if needed. Increase CPU and Memory values if you have enough resources. - - ```ruby - vb.memory = "5120" - vb.cpus = "4" - ``` - - 3. Start Box again. - - ```bash - host$ vagrant up - ``` - -C. (Optional) Setting Up Visual Studio Code -------------------------------------------- - -If you going to edit Ruby files, then it worth to install Visual Studio Code for macOS and Ruby plugin. - -1. Visual Studio Code: https://code.visualstudio.com -2. Ruby language support: https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby - -D. Getting Sources ------------------- - -1. Get Swift sources. - - **Note**: Steps taken from official [Guide](https://github.com/apple/swift). + **Note**: Usually you need to download box image once. ```bash - host$ mkdir -p Sources/swift - host$ cd Sources/swift - - host$ git clone https://github.com/apple/swift.git - host$ ./swift/utils/update-checkout --clone + host$ vagrant box add ubuntu/bionic64 ``` -2. Get Android NDK. - - 1. Download and Unpack archive. - - ```bash - host$ curl -O https://dl.google.com/android/repository/android-ndk-r18b-linux-x86_64.zip - host$ unzip -q -o android-ndk-*.zip - ``` - - 2. If you prefer manual download, then visit https://developer.android.com/ndk/downloads/. - - **Note**: At a time of writing this text there was release named: `android-ndk-r18b-linux-x86_64.zip` - - 3. Ensure that archive extracted to folder `Sources/android-ndk-r18b`. - - -3. Get ICU (International Components for Unicode). - - 1. Download and Unpack archive. + **Note**: You can explore trending boxes here: - ```bash - host$ curl -O http://download.icu-project.org/files/icu4c/63.1/icu4c-63_1-src.tgz - host$ tar -xzf icu4c-63_1-src.tgz - ``` + - https://app.vagrantup.com/boxes/search + - https://app.vagrantup.com/ubuntu/boxes/bionic64 - 2. If you prefer manual download, then visit http://site.icu-project.org/download - - **Note**: At a time of writing this text there was release named `ICU4C 63.1` and downloadable archive with sources named `icu4c-63_1-src.tgz`. - - 3. Ensure that archive extracted to folder `Sources/icu`. - - As result, file structure should be like below: - - ``` - ... - Sources - - android-ndk-r18b - - icu - - swift - ... - ``` - -4. Verify accessibility of sources inside Box. +4. Clone this repository. ```bash - box$ ls -l /vagrant/Sources + host$ git clone https://github.com/vgorloff/Android-On-Swift.git + host$ cd Android-On-Swift ``` -5. Verify environment variables inside Box. +5. (Optionall) Verify downloaded Ubuntu image in local folder. ```bash - box$ env | sort + host$ ls -l ~/.vagrant.d/boxes ``` - Should output: +6. Start box and connect via SSH. - ``` - ... - PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/vagrant/Sources/android-ndk-r18b - PWD=/home/vagrant - RUBYOPT=-W0 - SA_BUILD_ROOT_ANDK=/vagrant/Build/android-ndk - SA_BUILD_ROOT_ICU=/vagrant/Build/icu - SA_BUILD_ROOT_SWIFT=/vagrant/Build/swift-android - SA_BUILD_ROOT=/vagrant/Build - SA_INSTALL_ROOT_ANDK=/vagrant/Install/android-ndk - SA_INSTALL_ROOT_ICU=/vagrant/Install/icu - SA_INSTALL_ROOT_SWIFT=/vagrant/Install/swift - SA_INSTALL_ROOT=/vagrant/Install - SA_PATCHES_ROOT_ICU=/vagrant/Patches/icu - SA_PATCHES_ROOT=/vagrant/Patches - SA_PROJECTS_ROOT=/vagrant/Projects - SA_SOURCES_ROOT_ANDK=/vagrant/Sources/android-ndk-r18b - SA_SOURCES_ROOT_ICU=/vagrant/Sources/icu - SA_SOURCES_ROOT_SWIFT=/vagrant/Sources/swift - SA_SOURCES_ROOT=/vagrant/Sources - SHELL=/bin/bash - ... - ``` - -E. Installing dependencies on Box ---------------------------------------- + ```bash + host$ vagrant up + # (Optionall) Take snapshot. Under the hood it will save VirtualBox snapshot. -1. Install development packages and Verify Ruby and Rake version. + host$ vagrant snapshot save "Clean System" - ```bash host$ vagrant ssh - box$ bash /vagrant/Scripts/Shell/bootstrap.sh + # (Optionall) Explore synced folders. You should see this `Readme.md` file inside Ubuntu Box. + box$ ls -l /vagrant ``` -4. (Optionall) Take snapshot. + **Note**: Box will be created in directory specified in VirtualBox settings. Detalis in [this post](http://www.thisprogrammingthing.com/2013/changing-the-directory-vagrant-stores-the-vms-in/). - ```bash - host$ vagrant snapshot save "Initial Setup" - ``` - - **Note**: Under the hood it will save VirtualBox snapshot. +7. (Optional) Setting Up Visual Studio Code + + If you going to edit Ruby files, then it worth to install Visual Studio Code for macOS and Ruby plugin. -II. Usage -========= + - Visual Studio Code: https://code.visualstudio.com + - Ruby language support: https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby -Remaining process of compilling ICU and Swift, building and deploying sample projects automated via Rakefile. +8. Start a build. -```bash -box$ cd /vagrant/ -box$ rake -``` + **Note**: Process of compilling Swift Toolchain, building and deploying sample projects automated via Rakefile. -**Note**: Some Rake targets need to be executed on `host`, but some on `box`. Don't mix up execution environment. + ```bash + box$ cd /vagrant/ + box$ rake | more + ``` diff --git a/Scripts/ADBHelper.rb b/Scripts/ADBHelper.rb index eca7b778..97dd49f4 100755 --- a/Scripts/ADBHelper.rb +++ b/Scripts/ADBHelper.rb @@ -1,4 +1,3 @@ -require_relative "Common/Config.rb" require_relative "Common/Tool.rb" # See also: @@ -9,29 +8,30 @@ class ADBHelper < Tool def initialize() super() @destinationDirPath = "/data/local/tmp" + @swift = SwiftBuilder.new() + @ndk = AndroidBuilder.new() + @icu = ICUBuilder.new() end def verify() - # execute "sudo apt-get install android-tools-adb" - # execute "sudo adb devices" # To run daemon. + # On linux `execute "sudo apt-get install android-tools-adb"` + execute "adb devices" # To run daemon. message "Make sure you are enabled \"USB debugging\" on Android device (See :https://developer.android.com/studio/command-line/adb#Enabling)" execute "adb devices" # To list devices. end def deployLibs() - swiftBuildDirPath = "#{Config.swiftBuildRoot}/swift-linux-x86_64/lib/swift/android" - Dir[swiftBuildDirPath + "/*.so"].each { |lib| + Dir["#{@swift.installs}/usr/lib/swift/android" + "/*.so"].each { |lib| cmd = "adb push #{lib} #{@destinationDirPath}" execute cmd } - icuLibsDirPath = "#{Config.installRoot}/icu/armv7a/lib" - Dir[icuLibsDirPath + "/*.so*"].select { |lib| !File.symlink?(lib) } .each { |lib| + Dir[@icu.lib + "/*.so*"].select { |lib| !File.symlink?(lib) }.each { |lib| destName = File.basename(lib) destName = destName.sub("63.1", "63") # Fix for error: CANNOT LINK EXECUTABLE ... library "libicudataswift.so.63" not found cmd = "adb push #{lib} #{@destinationDirPath}/#{destName}" execute cmd } - cxxLibPath = "#{Config.ndkSourcesRoot}/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_shared.so" + cxxLibPath = "#{@ndk.sources}/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_shared.so" execute "adb push #{cxxLibPath} #{@destinationDirPath}" end diff --git a/Scripts/Builders/AndroidBuilder.rb b/Scripts/Builders/AndroidBuilder.rb index bb8aa925..f8f82a20 100755 --- a/Scripts/Builders/AndroidBuilder.rb +++ b/Scripts/Builders/AndroidBuilder.rb @@ -1,32 +1,37 @@ -require_relative "Builder.rb" -require_relative "../Common/Config.rb" +require_relative "../Common/Builder.rb" class AndroidBuilder < Builder - def initialize(arch) - super() - @arch = arch - @installDir = Config.installRoot + "/android/#{@arch}" + def api + return "21" end - def setupToolchain + def initialize(arch = Arch.default) + super(Lib.ndk, arch) + end + + def download() + downloader = Downloader.new(Config.downloads, @sources, "https://dl.google.com/android/repository/android-ndk-r18b-linux-x86_64.zip", 'android-ndk-*') + downloader.bootstrap() + end + + def setup cmd = [] - cmd << "#{Config.ndkSourcesRoot}/build/tools/make-standalone-toolchain.sh" - cmd << "--platform=android-#{Config.androidAPI}" - cmd << "--install-dir=#{@installDir}" - if @arch == "armv7a" + cmd << "#{@sources}/build/tools/make-standalone-toolchain.sh" + cmd << "--platform=android-#{api}" + cmd << "--install-dir=#{@installs}" + if @arch == Arch.armv7a cmd << "--toolchain=arm-linux-androideabi-4.9" - elsif @arch == "x86" + elsif @arch == Arch.x86 cmd << "--toolchain=x86-4.9" - elsif @arch == "aarch64" + elsif @arch == Arch.aarch64 cmd << "--toolchain=aarch64-linux-android-4.9" end execute cmd.join(" ") end def clean() - execute "rm -rf #{Config.buildRoot}/android/" - execute "rm -rf #{Config.installRoot}/android/" + execute "rm -rf \"#{@installs}/\"" end end diff --git a/Scripts/Builders/Builder.rb b/Scripts/Builders/Builder.rb deleted file mode 100755 index a0842555..00000000 --- a/Scripts/Builders/Builder.rb +++ /dev/null @@ -1,5 +0,0 @@ -require_relative "../Common/Tool.rb" - -class Builder < Tool - -end diff --git a/Scripts/Builders/CMarkBuilder.rb b/Scripts/Builders/CMarkBuilder.rb new file mode 100644 index 00000000..8bb5f744 --- /dev/null +++ b/Scripts/Builders/CMarkBuilder.rb @@ -0,0 +1,46 @@ +require_relative "../Common/Builder.rb" + +class CMarkBuilder < Builder + + def initialize(arch = Arch.default) + super(Lib.cmark, arch) + end + + def configure + # See: $SWIFT_REPO/docs/WindowsBuild.md + cmd = [] + cmd << "cd #{@builds} &&" + cmd << "cmake -G Ninja" + cmd << "-DCMAKE_INSTALL_PREFIX=#{@installs}" + cmd << "-DCMAKE_BUILD_TYPE=Release" + cmd << @sources + execute cmd.join(" ") + logConfigureCompleted + end + + def checkout + checkoutIfNeeded(@sources, "https://github.com/apple/swift-cmark.git", "32fa49671d0fc5d1f65d2bcbabfb1511a9d65c27") + end + + def build + execute "cd #{@builds} && ninja" + logBuildCompleted + end + + def install + execute "cd #{@builds} && ninja install" + logInstallCompleted + end + + def make + prepare + configure + build + install + end + + def prepare + execute "mkdir -p #{@builds}" + end + +end diff --git a/Scripts/Builders/ClangBuilder.rb b/Scripts/Builders/ClangBuilder.rb new file mode 100644 index 00000000..7e58c24b --- /dev/null +++ b/Scripts/Builders/ClangBuilder.rb @@ -0,0 +1,13 @@ +require_relative "../Common/Builder.rb" + +class ClangBuilder < Builder + + def initialize(arch = Arch.default) + super(Lib.clang, arch) + end + + def checkout + checkoutIfNeeded(@sources, "https://github.com/apple/swift-clang.git", "41ac4c42625c7a881ef7a9d2c8fe6f61daacbca0") + end + +end diff --git a/Scripts/Builders/CompilerRTBuilder.rb b/Scripts/Builders/CompilerRTBuilder.rb new file mode 100644 index 00000000..4de5a1ca --- /dev/null +++ b/Scripts/Builders/CompilerRTBuilder.rb @@ -0,0 +1,13 @@ +require_relative "../Common/Builder.rb" + +class CompilerRTBuilder < Builder + + def initialize(arch = Arch.default) + super(Lib.crt, arch) + end + + def checkout + checkoutIfNeeded(@sources, "https://github.com/apple/swift-compiler-rt.git", "d4667fe980efc317baf2641bc29ce1d41a1a0a6b") + end + +end diff --git a/Scripts/Builders/CurlBuilder.rb b/Scripts/Builders/CurlBuilder.rb new file mode 100644 index 00000000..0493fa7a --- /dev/null +++ b/Scripts/Builders/CurlBuilder.rb @@ -0,0 +1,64 @@ +require_relative "../Common/Builder.rb" + +class CurlBuilder < Builder + + def initialize(arch = Arch.default) + super(Lib.curl, arch) + end + + def checkout + checkoutIfNeeded(@sources, "https://github.com/curl/curl.git") + end + + def prepare + execute "mkdir -p #{@builds}" + end + + def commonArgs() + + end + + def configure + # Arguments took from `swift/swift-corelibs-foundation/build-android` + ndkToolchainPath = "#{Config.ndkInstallRoot}/#{@target}" + ndkToolchainBinPath = "#{ndkToolchainPath}/bin" + ndkToolchainSysPath = "#{ndkToolchainPath}/sysroot" + archFlags = "-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16" + ldFlags = "-march=armv7-a -Wl,--fix-cortex-a8" + cmd = ["cd #{@sourcesDir} &&"] + cmd << "PATH=#{ndkToolchainBinPath}:$PATH" + cmd << "CC=#{ndkToolchainBinPath}/arm-linux-androideabi-clang" + cmd << "CXX=#{ndkToolchainBinPath}/arm-linux-androideabi-clang++" + cmd << "AR=#{ndkToolchainBinPath}/arm-linux-androideabi-ar" + cmd << "AS=#{ndkToolchainBinPath}/arm-linux-androideabi-as" + cmd << "LD=#{ndkToolchainBinPath}/arm-linux-androideabi-ld" + cmd << "RANLIB=#{ndkToolchainBinPath}/arm-linux-androideabi-ranlib" + cmd << "NM=#{ndkToolchainBinPath}/arm-linux-androideabi-nm" + cmd << "STRIP=#{ndkToolchainBinPath}/arm-linux-androideabi-strip" + cmd << "CHOST=arm-linux-androideabi" + cmd << "CPPFLAGS=\"#{archFlags} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing\"" + cmd << "CXXFLAGS=\"#{archFlags} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -frtti -fexceptions -std=c++11 -Wno-error=unused-command-line-argument\"" + cmd << "CFLAGS=\"#{archFlags} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing\"" + cmd << "LDFLAGS=\"#{ldFlags}\"" + execute cmd.join(" ") + " autoreconf -i" + + cmd << "./configure" + cmd << "--host=arm-linux-androideabi --enable-shared --disable-static --disable-dependency-tracking --without-ca-bundle --without-ca-path --enable-ipv6 --enable-http --enable-ftp" + cmd << "--disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-proxy --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smtp --disable-gopher --disable-sspi --disable-manual" + cmd << "--target=arm-linux-androideabi --build=x86_64-unknown-linux-gnu" + cmd << "--with-zlib=#{ndkToolchainSysPath}/usr --with-ssl=#{Config.opensslSourcesRoot} --prefix=#{@installDir}" + execute cmd.join(" ") + end + + def build + execute "cd #{@sources} && make" + execute "cd #{@sources} && make install" + end + + def make + prepare + configure + build + end + +end diff --git a/Scripts/Builders/DispatchBuilder.rb b/Scripts/Builders/DispatchBuilder.rb new file mode 100644 index 00000000..149eacaf --- /dev/null +++ b/Scripts/Builders/DispatchBuilder.rb @@ -0,0 +1,77 @@ +require_relative "../Common/Builder.rb" + +# See: +# - Dispatch build script: https://github.com/readdle/swift-android-toolchain/blob/master/build/Linux/040_build_corelibs_libdispatch.sh +# - Cmake. Cross Compiling for Android: https://cmake.org/cmake/help/v3.7/manual/cmake-toolchains.7.html#id20 +class DispatchBuilder < Builder + + def initialize(arch = Arch.default) + super(Lib.dispatch, arch) + end + + def prepare + execute "mkdir -p #{@builds}" + end + + def args + @llvm = LLVMBuilder.new(arch) + @swift = SwiftBuilder.new(arch) + cmd = [] + cmd << "CLANG=\"#{@llvm.bin}/clang\"" + cmd << "CC=\"#{@llvm.bin}/clang\"" + cmd << "CXX=\"#{@llvm.bin}/clang++\"" + cmd << "SWIFT=\"#{@swift.bin}/swift\"" + cmd << "SWIFTC=\"#{@swift.bin}/swiftc\"" + return cmd + end + + def options + @llvm = LLVMBuilder.new(arch) + @swift = SwiftBuilder.new(arch) + @ndk = AndroidBuilder.new(arch) + # See: /swift/swift-corelibs-libdispatch/INSTALL.md + cmd = [] + cmd << "-DCMAKE_C_COMPILER=#{@llvm.bin}/clang -DCMAKE_CXX_COMPILER=#{@llvm.bin}/clang++" + cmd << "-DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a" + cmd << "-DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=clang" + cmd << "-DCMAKE_ANDROID_STL_TYPE=\"c++_static\"" + cmd << "-DCMAKE_BUILD_TYPE=Release" + cmd << "-DENABLE_SWIFT=true" + cmd << "-DCMAKE_SWIFT_COMPILER=\"#{@swift.bin}/swiftc\"" + cmd << "-DCMAKE_PREFIX_PATH=\"#{@swift.lib}/cmake/swift\"" + cmd << "-DCMAKE_INSTALL_PREFIX=#{@installs}" + cmd << "-DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=#{@ndk.api} -DCMAKE_ANDROID_NDK=#{@ndk.sources}" + return cmd + end + + def configure + cmd = [] + cmd << "cd #{@builds} &&" + cmd += args + cmd << "cmake -G Ninja" + cmd += options + cmd << @sources + execute cmd.join(" ") + end + + def build + # See: What is CMake equivalent of 'configure --prefix=DIR && make all install: https://stackoverflow.com/a/35753015/1418981 + execute "cd #{@build} && cmake " + options.join(" ") + " . && " + args.join(" ") + " ninja install" + end + + def make + prepare + configure + build + end + + def clean + execute "rm -rf \"#{@builds}\"" + execute "rm -rf \"#{@installs}\"" + end + + def checkout + checkoutIfNeeded(@sources, "https://github.com/apple/swift-corelibs-libdispatch.git", "afa6cc3d1c42935c5a1016ec7ae13ddcbb1853d4") + end + +end diff --git a/Scripts/Builders/FoundationBuilder.rb b/Scripts/Builders/FoundationBuilder.rb new file mode 100644 index 00000000..fe856cae --- /dev/null +++ b/Scripts/Builders/FoundationBuilder.rb @@ -0,0 +1,112 @@ +require_relative "../Common/Builder.rb" + +# See: +# - Libdispatch issues with CMake: https://forums.swift.org/t/libdispatch-switched-to-cmake/6665/7 +class FoundationBuilder < Builder + + def initialize(arch = Arch.default) + super(Lib.foundation, arch) + @ndk = AndroidBuilder.new(arch) + @dispatch = DispatchBuilder.new(arch) + @swift = SwiftBuilder.new(arch) + @curl = CurlBuilder.new(arch) + @icu = ICUBuilder.new(arch) + @xml = XMLBuilder.new(arch) + @llvm = LLVMBuilder.new(arch) + end + + def prepare + execute "mkdir -p #{@build}" + copyFiles + end + + def copyFiles + usr = @ndk.install + "/sysroot/usr" + # Copy dispatch public and private headers to the directory foundation is expecting to get it + targetDir = "#{usr}/include/dispatch" + execute "mkdir -p #{targetDir}" + execute "cp -v #{@dispatch.sources}/dispatch/*.h #{targetDir}" + execute "cp -v #{@dispatch.sources}/private/*.h #{targetDir}" + + # libFoundation script is not completely prepared to handle cross compilation yet. + execute "ln -svf #{@swift.lib}/swift #{usr}/lib/" + execute "cp -vr #{@swift.lib}/swift/android/armv7/* #{@swift.lib}/swift/android/" + + # Search path for curl seems to be wrong in foundation + execute "cp -rv #{@curl.include}/curl #{usr}/include" + execute "ln -fvs #{usr}/include/curl #{usr}/include/curl/curl" + + execute "cp -rv #{@xml.include}/libxml2 #{usr}/include" + execute "ln -fvs #{usr}/include/libxml2/libxml #{usr}/include/libxml" + + execute "cp -vr /usr/include/uuid #{usr}/include" + end + + def args + # Arguments took from `swift/swift-corelibs-foundation/build-android` + sysroot = @ndk.install + "/sysroot" + cmd = [] + cmd << "cd #{@sources} && env" + cmd << "BUILD_DIR=#{@build}" + cmd << "DSTROOT=#{@install}" + + cmd << "SWIFTC=\"#{@swift.bin}/swiftc\"" + cmd << "CLANG=\"#{@llvm.bin}/clang\"" + # cmd << "CLANGXX=\"#{@llvm.bin}/clang++\"" + cmd << "SWIFT=\"#{@swift.bin}/swift\"" + cmd << "SDKROOT=\"#{@swift.install}\"" + cmd << "CFLAGS=\"-DDEPLOYMENT_TARGET_ANDROID -DDEPLOYMENT_ENABLE_LIBDISPATCH --sysroot=#{sysroot} -I#{@icu.include} -I#{@swift.lib}/swift -I#{@ndk.sources}/sources/android/support/include -I#{sysroot}/usr/include -I#{@sources}/closure\"" + cmd << "SWIFTCFLAGS=\"-DDEPLOYMENT_TARGET_ANDROID -DDEPLOYMENT_ENABLE_LIBDISPATCH -Xcc -DDEPLOYMENT_TARGET_ANDROID -I#{sysroot}/usr/include\"" + cmd << "LDFLAGS=\"-fuse-ld=gold --sysroot=#{sysroot} -L#{@ndk.sources}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x -L#{@icu.lib} -L#{sysroot}/usr/lib -ldispatch\"" + return cmd + end + + def configure + sysroot = @ndk.install + "/sysroot" + cmd = args + cmd << "./configure Release --target=armv7-none-linux-androideabi --sysroot=#{sysroot}" + # cmd << "-DXCTEST_BUILD_DIR=#{swiftCCRoot}/xctest-linux-x86_64" + cmd << "-DLIBDISPATCH_SOURCE_DIR=#{@dispatch.sources}" + cmd << "-DLIBDISPATCH_BUILD_DIR=#{@dispatch.install}" + execute cmd.join(" ") + + execute "cd #{@sourcesDir} && sed --in-place 's/-I\\/usr\\/include\\/x86_64-linux-gnu//' build.ninja" + execute "cd #{@sourcesDir} && sed --in-place 's/-I\\/usr\\/include\\/libxml2//' build.ninja" + execute "cd #{@sourcesDir} && sed --in-place 's/-I.\\///' build.ninja" + execute "cd #{@sourcesDir} && sed --in-place 's/-licui18n/-licui18nswift/g' build.ninja" + execute "cd #{@sourcesDir} && sed --in-place 's/-licuuc/-licuucswift/g' build.ninja" + execute "cd #{@sourcesDir} && sed --in-place 's/-licudata/-licudataswift/g' build.ninja" + end + + def compile + execute args.join(" ") + " ninja CopyHeaders" + + # Patching module.modulemap file. + message "Patching module.modulemap file." + headersPath = "#{@build}/Foundation/usr/lib/swift/CoreFoundation" + moduleMapPath = headersPath + "/module.modulemap" + contents = File.readlines(moduleMapPath).join() + contents = contents.sub('"CoreFoundation.h"', '"' + headersPath + '/CoreFoundation.h"') + contents = contents.sub('"CFPlugInCOM.h"', '"' + headersPath + '/CFPlugInCOM.h"') + File.write(moduleMapPath, contents) + + # Running build. + execute args.join(" ") + " ninja" + end + + def make + prepare + configure + compile + end + + def clean + execute "rm -rf \"#{@build}\"" + execute "rm -rf \"#{@install}\"" + end + + def checkout + checkoutIfNeeded(@sources, "https://github.com/apple/swift-corelibs-foundation", "a7f12d0851780b2c196733b2710a8ff2ae56bdcd") + end + +end diff --git a/Scripts/Builders/HelloProjectBuilder.rb b/Scripts/Builders/HelloProjectBuilder.rb new file mode 100755 index 00000000..31f23aba --- /dev/null +++ b/Scripts/Builders/HelloProjectBuilder.rb @@ -0,0 +1,37 @@ +require_relative "../Common/Builder.rb" + +# See: +# - Build error: No such module "SwiftGlibc" – https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20160919/002955.html +class HelloProjectBuilder < Builder + + attr_reader :executable, :executableName + + def initialize(arch = Arch.default) + super("Hello", arch) + @executableName = "hello" + @executable = @builds + "/" + @executableName + @projectRoot = "#{Config.projects}/Hello" + end + + def build + prepare + swift = SwiftBuilder.new() + ndk = AndroidBuilder.new() + cmd = ["cd #{@builds} &&"] + cmd << "PATH=#{swift.installs}/usr/bin:$PATH" + cmd << "swiftc" + cmd << "-tools-directory #{ndk.sources}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/arm-linux-androideabi/bin" + cmd << "-target armv7-none-linux-androideabi" # Targeting android-armv7. + cmd << "-sdk #{ndk.sources}/platforms/android-#{ndk.api}/arch-arm" # Use the same NDK path and API version as you used to build the stdlib in the previous step. + cmd << "-L #{ndk.sources}/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a" # Link the Android NDK's libc++ and libgcc. + cmd << "-L #{ndk.sources}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x" + cmd << "#{@projectRoot}/hello.swift" + execute cmd.join(" ") + execute "readelf -h #{@executable}" + end + + def prepare() + execute "mkdir -p #{@builds}" + end + +end diff --git a/Scripts/Builders/ICUBuilder.rb b/Scripts/Builders/ICUBuilder.rb index f65e1487..1fd745bc 100755 --- a/Scripts/Builders/ICUBuilder.rb +++ b/Scripts/Builders/ICUBuilder.rb @@ -1,5 +1,4 @@ -require_relative "Builder.rb" -require_relative "../Common/Config.rb" +require_relative "../Common/Builder.rb" # See: # - ICU Patches: https://github.com/amraboelela/swift/blob/android/docs/Android.md @@ -12,23 +11,45 @@ class ICUBuilder < Builder - def initialize(target = "armv7a") - super() - @target = target - @buildDir = Config.buildRoot + "/icu/" + @target - @prefixDir = Config.installRoot + "/icu/" + @target + def initialize(arch = Arch.default) + super(Lib.icu, arch) + @gitRepoRoot = "#{Config.sources}/#{Lib.icu}" + @sources = "#{@gitRepoRoot}/icu4c" + @ndk = AndroidBuilder.new(arch) + if arch != Arch.host + @host = ICUBuilder.new(Arch.host) + end + end + + def configureHost + prepare + applyPatchIfNeeded(false) + cmd = ["cd #{@builds} &&"] + cmd << 'CC="/usr/bin/clang"' + cmd << 'CXX="/usr/bin/clang++"' + cmd << 'CFLAGS="-Os"' + cmd << 'CXXFLAGS="--std=c++11"' + cmd << "#{@sources}/source/runConfigureICU Linux --prefix=#{@installs}" + cmd << "--enable-static --enable-shared=no --enable-extras=no --enable-strict=no --enable-icuio=no --enable-layout=no" + cmd << "--enable-layoutex=no --enable-tools=no --enable-tests=no --enable-samples=no --enable-dyload=no" + execute cmd.join(" ") end def configure - cmd = ["cd #{@buildDir} &&"] - if @target == "linux" - cmd << 'CFLAGS="-Os"' - cmd << 'CXXFLAGS="--std=c++11"' - cmd << "#{Config.icuSourcesRoot}/source/runConfigureICU Linux --prefix=#{@prefixDir}" - cmd << "--enable-static --enable-shared=no --enable-extras=no --enable-strict=no --enable-icuio=no --enable-layout=no" - cmd << "--enable-layoutex=no --enable-tools=no --enable-tests=no --enable-samples=no --enable-dyload=no" - elsif @target == "armv7a" - cmd << "PATH=#{Config.installRoot}/android/#{@target}/bin:$PATH" + if !@host.nil? && !File.exist?(@host.bin) + message "Building Corss-Build Host." + @host.configureHost + @host.build + @host.install + message "Corss-Build Host Build completed." + end + + prepare + applyPatchIfNeeded(false) + applyPatchIfNeeded + cmd = ["cd #{@builds} &&"] + cmd << "PATH=#{@ndk.installs}/bin:$PATH" + if @arch == Arch.armv7a cmd << "CFLAGS='-Os -march=armv7-a -mfloat-abi=softfp -mfpu=neon'" cmd << "CXXFLAGS='--std=c++11 -march=armv7-a -mfloat-abi=softfp -mfpu=neon'" cmd << "LDFLAGS='-march=armv7-a -Wl,--fix-cortex-a8'" @@ -36,78 +57,87 @@ def configure cmd << "CXX=arm-linux-androideabi-clang++" cmd << "AR=arm-linux-androideabi-ar" cmd << "RINLIB=arm-linux-androideabi-ranlib" - cmd << "#{Config.icuSourcesRoot}/source/configure --prefix=#{@prefixDir}" + cmd << "#{@sources}/source/configure --prefix=#{@installs}" cmd << "--host=arm-linux-androideabi" - cmd << "--with-library-suffix=swift" - cmd << "--enable-static --enable-shared --enable-extras=no --enable-strict=no --enable-icuio=no --enable-layout=no --enable-layoutex=no" - cmd << "--enable-tools=no --enable-tests=no --enable-samples=no --enable-dyload=no" - cmd << "--with-cross-build=#{Config.buildRoot}/icu/linux" - cmd << "--with-data-packaging=archive" - elsif @target == "x86" - cmd << "PATH=#{Config.installRoot}/android/#{@target}/bin:$PATH" + elsif @arch == Arch.x86 cmd << "CFLAGS='-Os -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32'" cmd << "CXXFLAGS='--std=c++11 -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32'" cmd << "CC=i686-linux-android-clang" cmd << "CXX=i686-linux-android-clang++" cmd << "AR=i686-linux-android-ar" cmd << "RINLIB=i686-linux-android-ranlib" - cmd << "#{Config.icuSourcesRoot}/source/configure --prefix=#{@prefixDir}" + cmd << "#{@sources}/source/configure --prefix=#{@installs}" cmd << "--host=i686-linux-android" - cmd << "--with-library-suffix=swift" - cmd << "--enable-static --enable-shared --enable-extras=no --enable-strict=no --enable-icuio=no --enable-layout=no --enable-layoutex=no" - cmd << "--enable-tools=no --enable-tests=no --enable-samples=no --enable-dyload=no" - cmd << "--with-cross-build=#{Config.buildRoot}/icu/linux" - cmd << "--with-data-packaging=archive" - elsif @target == "aarch64" - cmd << "PATH=#{Config.installRoot}/android/#{@target}/bin:$PATH" + elsif @arch == Arch.aarch64 cmd << "CFLAGS='-Os'" cmd << "CXXFLAGS='--std=c++11'" cmd << "CC=aarch64-linux-android-clang" cmd << "CXX=aarch64-linux-android-clang++" cmd << "AR=aarch64-linux-android-ar" cmd << "RINLIB=aarch64-linux-android-ranlib" - cmd << "#{Config.icuSourcesRoot}/source/configure --prefix=#{@prefixDir}" + cmd << "#{@sources}/source/configure --prefix=#{@installs}" cmd << "--host=aarch64-linux-android" - cmd << "--with-library-suffix=swift" - cmd << "--enable-static --enable-shared --enable-extras=no --enable-strict=no --enable-icuio=no --enable-layout=no --enable-layoutex=no" - cmd << "--enable-tools=no --enable-tests=no --enable-samples=no --enable-dyload=no" - cmd << "--with-cross-build=#{Config.buildRoot}/icu/linux" - cmd << "--with-data-packaging=archive" end + cmd << "--with-library-suffix=swift" + cmd << "--enable-static --enable-shared --enable-extras=no --enable-strict=no --enable-icuio=no --enable-layout=no --enable-layoutex=no" + cmd << "--enable-tools=no --enable-tests=no --enable-samples=no --enable-dyload=no" + cmd << "--with-cross-build=#{@host.builds}" + cmd << "--with-data-packaging=archive" execute cmd.join(" ") + logConfigureCompleted + end + + def checkout + checkoutIfNeeded(@gitRepoRoot, "https://github.com/unicode-org/icu.git", "2e86b08fcda87e279efdcb8f9f3310cb6b9150af") end def prepare() - execute "mkdir -p #{@buildDir}" - applyPatchIfNeeded() + execute "mkdir -p #{@builds}" end - def applyPatchIfNeeded() - originalFile = "#{Config.icuSourcesRoot}/source/configure" - backupFile = "#{Config.icuSourcesRoot}/source/configure.orig" - patchFile = "#{Config.icuPatchesRoot}/configure.patch" - if !File.exist? backupFile - puts "Patching ICU..." - execute "patch --backup #{originalFile} #{patchFile}" + def applyPatchIfNeeded(shouldApply = true) + originalFile = "#{@sources}/source/configure" + backupFile = "#{@sources}/source/configure.orig" + patchFile = "#{@patches}/configure.patch" + if shouldApply + if !File.exist? backupFile + puts "Patching ICU..." + execute "patch --backup #{originalFile} #{patchFile}" + else + puts "Backup file \"#{backupFile}\" exists. Seems you already patched ICU. Skipping..." + end else - puts "Backup file \"#{backupFile}\" exists. Seems you already patched ICU. Skipping..." + message "Removing previously applied patch..." + execute "cd \"#{@gitRepoRoot}\" && git checkout #{originalFile}" + if File.exist? backupFile + execute "rm -fv #{backupFile}" + end end end def build - execute "cd #{@buildDir} && PATH=#{Config.installRoot}/android/#{@target}/bin:$PATH make -j4" - execute "cd #{@buildDir} && PATH=#{Config.installRoot}/android/#{@target}/bin:$PATH make install" + prepare + execute "cd #{@builds} && PATH=#{@ndk.installs}/bin:$PATH make -j4" + logBuildCompleted end - def make() - prepare + def install + execute "cd #{@builds} && PATH=#{@ndk.installs}/bin:$PATH make install" + logInstallCompleted + end + + def make configure build + install end - def clean() - execute "rm -rf #{Config.buildRoot}/icu/" - execute "rm -rf #{Config.installRoot}/icu/" + def clean + if !@host.nil? + @host.clean + end + execute "rm -rf #{@builds}" + execute "rm -rf #{@installs}" end end diff --git a/Scripts/Builders/LLVMBuilder.rb b/Scripts/Builders/LLVMBuilder.rb new file mode 100644 index 00000000..076d6de6 --- /dev/null +++ b/Scripts/Builders/LLVMBuilder.rb @@ -0,0 +1,64 @@ +require_relative "../Common/Builder.rb" + +class LLVMBuilder < Builder + + def initialize(arch = Arch.default) + super(Lib.llvm, arch) + end + + def configure + # See: + # - LLVM Getting Started: https://llvm.org/docs/GettingStarted.html#requirements + # - CLANG Getting Started: http://clang.llvm.org/get_started.html + cmd = [] + cmd << "cd #{@builds} &&" + cmd << "cmake -G Ninja" + cmd << "-DCMAKE_INSTALL_PREFIX=#{@installs}" + cmd << "-DCMAKE_BUILD_TYPE=Release" + # See: https://stackoverflow.com/questions/40122657/build-llvm-clang4-0-for-android-armeabi + # Line below still cause build failure. + cmd << "-DLLVM_TARGETS_TO_BUILD=\"ARM;AArch64;X86\"" + # cmd << "-DLLVM_DEFAULT_TARGET_TRIPLE=\"arm-linux-androideabi\"" + cmd << @sources + execute cmd.join(" ") + logConfigureCompleted() + end + + def build + execute "cd #{@builds} && ninja" + logBuildCompleted() + end + + def install + execute "cd #{@builds} && ninja install" + logInstallCompleted() + end + + def make + prepare + configure + build + install + end + + def checkout + checkoutIfNeeded(@sources, "https://github.com/apple/swift-llvm.git", "f63b283c7143aef31863d5915c28ee79ed390be3") + end + + def prepare() + execute "mkdir -p #{@builds}" + # Making needed SymLinks. See: https://llvm.org/docs/GettingStarted.html#git-mirror + message "Making symbolic links..." + @clang = ClangBuilder.new() + @crt = CompilerRTBuilder.new() + execute "ln -svf \"#{@clang.sources}\" \"#{@sources}/tools/clang\"" + execute "ln -svf \"#{@crt.sources}\" \"#{@sources}/projects/compiler-rt\"" + message "LLVM Prepare is Done!" + end + + def clean + execute "rm -rf #{@builds}" + execute "rm -rf #{@installs}" + end + +end diff --git a/Scripts/Builders/OpenSSLBuilder.rb b/Scripts/Builders/OpenSSLBuilder.rb new file mode 100644 index 00000000..d1e4c272 --- /dev/null +++ b/Scripts/Builders/OpenSSLBuilder.rb @@ -0,0 +1,59 @@ +require_relative "../Common/Builder.rb" + +# See: +# - Compiling the latest OpenSSL for Android: https://stackoverflow.com/questions/11929773/compiling-the-latest-openssl-for-android + +class OpenSSLBuilder < Builder + + def initialize(target = "armv7a") + super() + @target = target + @sourcesDir = Config.opensslSourcesRoot + @buildDir = Config.buildRoot + "/openssl/" + @target + @installDir = Config.installRoot + "/openssl/" + @target + end + + def checkout + downloader = Downloader.new(Config.sourcesRoot, Config.opensslSourcesRoot, "https://github.com/openssl/openssl/archive/OpenSSL_1_1_1a.tar.gz", 'openssl-*') + downloader.bootstrap() + end + + def prepare + execute "mkdir -p #{@buildDir}" + execute "mkdir -p #{@installDir}" + end + + def configure + execute commonArgs.join(" ") + " ./Configure -D__ANDROID_API__=#{Config.androidAPI} --prefix=#{@installDir} android-arm" + end + + def commonArgs() + ndkToolchainPath = "#{Config.ndkInstallRoot}/#{@target}" + ndkToolchainBinPath = "#{ndkToolchainPath}/bin" + archFlags = "-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16" + ldFlags = "-march=armv7-a -Wl,--fix-cortex-a8" + cmd = ["cd #{@sourcesDir} &&"] + cmd << "ANDROID_NDK=#{ndkToolchainPath}" + cmd << "PATH=#{ndkToolchainBinPath}:$PATH" + # >> Seems not needed + cmd << "CPPFLAGS=\"#{archFlags} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing\"" + cmd << "CXXFLAGS=\"#{archFlags} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -frtti -fexceptions -std=c++11 -Wno-error=unused-command-line-argument\"" + cmd << "CFLAGS=\"#{archFlags} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing\"" + cmd << "LDFLAGS=\"#{ldFlags}\"" + # << + return cmd + end + + def build + execute commonArgs.join(" ") + " make -j4" + execute commonArgs.join(" ") + " make install" + end + + def make + checkout + prepare + configure + build + end + +end diff --git a/Scripts/Builders/SwiftBuilder.rb b/Scripts/Builders/SwiftBuilder.rb index 5de4c1b4..e0cf5eb8 100755 --- a/Scripts/Builders/SwiftBuilder.rb +++ b/Scripts/Builders/SwiftBuilder.rb @@ -1,101 +1,213 @@ -require_relative "Builder.rb" -require_relative "../Common/Config.rb" +require_relative "../Common/Builder.rb" =begin -Compiling swift on Linux: https://akrabat.com/compiling-swift-on-linux/ - -# See: -# 1. Building the Swift stdlib for Android – https://github.com/amraboelela/swift/blob/android/docs/Android.md -# 2. fuchsia build – https://fuchsia.googlesource.com/third_party/swift-corelibs-foundation/+/upstream/google/build-android -# 3. Port to Android Patch – https://github.com/SwiftAndroid/swift/commit/7c502b6344a240c8e06c5e48e5ab6fa32c887ab3 -# 4. Using Swift to Build Code for Android – https://www.infoq.com/news/2016/04/swift-for-android -# 5. Issue with lg.gold – https://bugs.swift.org/browse/SR-1264?page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel&showAll=true -# 6. Ussue with ld.gold – https://github.com/apple/swift/commit/d49d88e53d15b6cba00950ec7985df4631e24312 -# 7. Cross compile Apps on Mac for Linux: https://github.com/apple/swift-package-manager/blob/master/Utilities/build_ubuntu_cross_compilation_toolchain -# 8. Swift cross compile on Rasperi Pi: https://stackoverflow.com/a/44003655/1418981 -# 9. Java and Swift interoperability: https://medium.com/@michiamling/android-app-with-java-native-interface-for-swift-c9c322609e08 - -Swift in Java. - -- https://romain.goyet.com/articles/running_swift_code_on_android/ +Swift for Linux: +- Compiling swift on Linux: https://akrabat.com/compiling-swift-on-linux/ +- Build Swift for Android from your Mac: https://github.com/flowkey/swift-android-toolchain + +Swift for Android: +- See ./Sources/Swift/swift/utils/android/build-toolchain +- Running Swift code on Android https://romain.goyet.com/articles/running_swift_code_on_android/ +- Building a Development Environment for Swift on Android: https://medium.com/@michiamling/building-a-development-environment-for-swift-on-android-4bb652d2c938 +- Java and Swift interoperability: https://medium.com/@michiamling/android-app-with-java-native-interface-for-swift-c9c322609e08 +- Android App with Java native interface for Swift: http://michis.culture-blog.org/2017/04/android-app-with-java-native-interface.html +- Building the Swift stdlib for Android – https://github.com/amraboelela/swift/blob/android/docs/Android.md +- fuchsia build – https://fuchsia.googlesource.com/third_party/swift-corelibs-foundation/+/upstream/google/build-android - https://www.reddit.com/r/swift/comments/3w0xrd/im_patching_the_opensource_swift_compiler_to/ - https://github.com/flowkey/UIKit-cross-platform -- https://github.com/flowkey/swift-android-toolchain - https://blog.readdle.com/why-we-use-swift-for-android-db449feeacaf +- Swift on Android: The Future of Cross-Platform Programming?: https://academy.realm.io/posts/swift-on-android/ +Pull Requests and Patches: +- Port to Android Patch: https://github.com/SwiftAndroid/swift/commit/7c502b6344a240c8e06c5e48e5ab6fa32c887ab3 -~~OLD +Issues: +- Issue with lg.gold – https://bugs.swift.org/browse/SR-1264 +- Issue with ld.gold – https://github.com/apple/swift/commit/d49d88e53d15b6cba00950ec7985df4631e24312 -./swift/utils/build-script --show-presets (see also swift/utils/build-presets.ini) - -5. Build: ./swift/utils/build-script --preset=buildbot_linux installable_package=~/swift.tar.gz install_destdir=~/swift-install -5. Build: ./swift/utils/build-script --preset=buildbot_linux,no_test installable_package=~/swift.tar.gz install_destdir=~/swift-install - -# ./swift/utils/build-script -# --assertions --no-swift-stdlib-assertions --swift-enable-ast-verifier=0 -# --llbuild --swiftpm --xctest --libicu --build-ninja --install-swift --install-lldb --install-llbuild -# --install-swiftpm --install-xctest --install-libicu -# --install-prefix=/usr '--swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;swift-remote-mirror;sdk-overlay;license;sourcekit-inproc' -# '--llvm-install-components=llvm-cov;llvm-profdata;IndexStore' -# --build-swift-static-stdlib --build-swift-static-sdk-overlay --build-swift-stdlib-unittest-extra -# --test-installable-package -# --install-destdir=/home/user/Developer/Install/swift/swift5-android -# --installable-package=/home/user/Developer/Install/swift/swift5-android.tar.gz -# --build-subdir=buildbot_linux --lldb --release +Cross compile: +- Cross compile Apps on Mac for Linux: https://github.com/apple/swift-package-manager/blob/master/Utilities/build_ubuntu_cross_compilation_toolchain +- Swift cross compile on Rasperi Pi: https://stackoverflow.com/a/44003655/1418981 =end class SwiftBuilder < Builder - def initialize() - super() - @installRoot = Config.installRoot + "/swift/swift" - @installArchive = Config.installRoot + "/swift/swift.tar.gz" + def initialize(arch = Arch.default) + super(Lib.swift, arch) + @icu = ICUBuilder.new(arch) + @ndk = AndroidBuilder.new(arch) end - def build() - target = "armv7a" - libICUBuildPath = Config.installRoot + "/icu/#{target}/lib" - cmd = ["cd #{Config.swiftSourcesRoot} &&"] - cmd << "./swift/utils/build-script --release --android" - cmd << "--android-ndk #{Config.ndkSourcesRoot}" - cmd << "--android-api-level #{Config.androidAPI}" - cmd << "--android-icu-uc #{libICUBuildPath}/libicuucswift.so" - cmd << "--android-icu-uc-include #{Config.icuSourcesRoot}/source/common" - cmd << "--android-icu-i18n #{libICUBuildPath}/libicui18nswift.so" - cmd << "--android-icu-i18n-include #{Config.icuSourcesRoot}/source/i18n" - cmd << "--android-icu-data #{Config.icuSourcesRoot}/libicudataswift.so" - # cmd << "--foundation --libdispatch" # Needs to be compiled separately. - cmd << "--build-dir #{Config.swiftBuildRoot}" + def compileOLD + cmd = ["cd #{@sources} &&"] + # To avoid issue: + # /usr/bin/ld.gold: fatal error: /vagrant/Sources/ndk/platforms/android-21/arch-arm/usr/lib/../lib/crtbegin_so.o: unsupported ELF machine number 40 + cmd << "env PATH=#{@ndk.install}/arm-linux-androideabi/bin:$PATH" + end + + def configureOld + # See: SWIFT_GIT_ROOT/docs/WindowsBuild.md + cmd = [] + cmd << "cd #{@builds} &&" + cmd << "cmake -G Ninja" + + # cmd << "-DCMAKE_C_COMPILER=\"#{@llvm.bin}/clang\"" + # cmd << "-DCMAKE_CXX_COMPILER=\"#{@llvm.bin}/clang++\"" + + cmd << "-DCMAKE_C_COMPILER=/usr/bin/clang" + cmd << "-DCMAKE_CXX_COMPILER=/usr/bin/clang++" + + # See: + # - https://stackoverflow.com/questions/10712972/what-is-the-use-of-fno-stack-protector + # - https://reviews.llvm.org/D34264 + # - https://bugzilla.mozilla.org/show_bug.cgi?id=731316 + cFlags = "-Wno-unknown-warning-option -Werror=unguarded-availability-new -fno-stack-protector" + cmd << "-DCMAKE_C_FLAGS=\"#{cFlags}\"" + cmd << "-DCMAKE_CXX_FLAGS=\"#{cFlags}\"" + + # cmd << "-DCLANG_VERSION_MAJOR=\"7\" -DCLANG_VERSION_MINOR=\"0\" -DCLANG_VERSION_PATCH=\"0\"" + + # cmd << "-DCMAKE_CXX_FLAGS="-Wno-c++98-compat -Wno-c++98-compat-pedantic"^ + # cmd << "-DCMAKE_EXE_LINKER_FLAGS:STRING="/INCREMENTAL:NO"^ + # cmd << "-DCMAKE_SHARED_LINKER_FLAGS="/INCREMENTAL:NO"^ + cmd << "-DCMAKE_INSTALL_PREFIX=\"#{@installs}\"" + cmd << "-DCMAKE_BUILD_TYPE=Release" + cmd << "-DSWIFT_INCLUDE_TESTS=NO" + cmd << "-DSWIFT_INCLUDE_DOCS=NO" + cmd << "-DSWIFT_BUILD_SOURCEKIT=NO" + cmd << "-DSWIFT_BUILD_SYNTAXPARSERLIB=NO" + + # Making Ninja verbose. See: https://github.com/ninja-build/ninja/issues/900#issuecomment-132346047 + # cmd << "-DCMAKE_VERBOSE_MAKEFILE=ON" + + cmd << "-DSWIFT_PATH_TO_LLVM_SOURCE=\"#{@llvm.sources}\"" + cmd << "-DSWIFT_PATH_TO_LLVM_BUILD=\"#{@llvm.builds}\"" + + cmd << "-DSWIFT_PATH_TO_CMARK_SOURCE=\"#{@cmark.sources}\"" + cmd << "-DSWIFT_PATH_TO_CMARK_BUILD=\"#{@cmark.builds}\"" + cmd << "-DSWIFT_CMARK_LIBRARY_DIR=\"#{@cmark.lib}\"" + + cmd << "-DSWIFT_SDKS=LINUX" + + # Seems these vars is unused. + cmd << "-DSWIFT_EXEC=#{@builds}/bin/swiftc" + cmd << "-DLIBDISPATCH_CMAKE_BUILD_TYPE=Release" + + # cmd << "-DSWIFT_PATH_TO_CLANG_SOURCE=\"#{@clang.sources}\"" + cmd << "-DSWIFT_PATH_TO_LIBDISPATCH_SOURCE=\"#{@dispatch.sources}\"" + # cmd << "-DSWIFT_PATH_TO_CLANG_BUILD=\"#{@llvm.builds}\"" + # cmd << "-DLLVM_BUILD_LIBRARY_DIR=\"#{@llvm.lib}\"" + # cmd << "-DLLVM_BUILD_MAIN_INCLUDE_DIR=\"#{@llvm.include}\"" + # cmd << "-DLLVM_BUILD_BINARY_DIR=\"#{@llvm.bin}\"" + # cmd << "-DLLVM_BUILD_MAIN_SRC_DIR=\"#{@llvm.sources}\"" + + # Both lines not needed after setting C/CXX compillers + # cmd << "-DCMAKE_PREFIX_PATH=#{@llvm.lib}/cmake/clang" + # cmd << "-DClang_DIR=#{@llvm.lib}/cmake/clang" + # + # -DSWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE="%swift_source_dir%/icu/include"^ + # -DSWIFT_WINDOWS_x86_64_ICU_UC="%swift_source_dir%/icu/lib64/icuuc.lib"^ + # -DSWIFT_WINDOWS_x86_64_ICU_I18N_INCLUDE="%swift_source_dir%/icu/include"^ + # -DSWIFT_WINDOWS_x86_64_ICU_I18N="%swift_source_dir%/icu/lib64/icuin.lib"^ + cmd << @sources execute cmd.join(" ") + logConfigureCompleted end - def prepare() - targetFile = "/usr/bin/armv7-none-linux-androideabi-ld.gold" - if File.exist?(targetFile) - return + def build + cmd = ["cd #{@sources} &&"] + cmd << "SKIP_BUILD_SWIFT_STATIC_LIBDISPATCH=1 SKIP_BUILD_STATIC_FOUNDATION=1" + cmd << "./utils/build-script --release --skip-reconfigure" + # cmd << "--dry-run" + # cmd << "--verbose-build" + cmd << "--assertions --no-swift-stdlib-assertions --swift-enable-ast-verifier=0" + + if @arch != Arch.host + cmd << "--android" + cmd << "--android-ndk #{@ndk.sources}" + cmd << "--android-api-level #{@ndk.api}" + cmd << "--android-icu-uc #{@icu.lib}/libicuucswift.so" + cmd << "--android-icu-uc-include #{@icu.sources}/source/common" + cmd << "--android-icu-i18n #{@icu.lib}/libicui18nswift.so" + cmd << "--android-icu-i18n-include #{@icu.sources}/source/i18n" + cmd << "--android-icu-data #{@icu.lib}/libicudataswift.so" end - puts "Making symbolic link to \"#{targetFile}\"..." - cmd = ["sudo"] - cmd << "ln -s #{Config.ndkSourcesRoot}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/arm-linux-androideabi/bin/ld.gold" - cmd << targetFile + cmd << "--install-swift" + cmd << "--libdispatch --install-libdispatch" + cmd << "--foundation --install-foundation" + + # Try without it. + cmd << "--build-swift-static-stdlib --build-swift-static-sdk-overlay" + + # Try it + # cmd << "--test false" + # cmd << "--skip-test-cmark --skip-test-lldb --skip-test-swift --skip-test-llbuild --skip-test-swiftpm --skip-test-xctest" + # cmd << "--skip-test-foundation --skip-test-libdispatch --skip-test-playgroundsupport --skip-test-libicu" + + # TODO: Try it + cmd << '--llvm-targets-to-build="ARM;AArch64;X86"' + # TODO: Try it + # cmd << "--skip-test-android-host" + + # cmd << "--llbuild --install-llbuild" + # cmd << "--lldb --install-lldb" + # cmd << "--swiftpm --install-swiftpm" + # cmd << "--xctest --install-xctest" + + # cmd << "'--swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;swift-remote-mirror;sdk-overlay;license;sourcekit-inproc'" + cmd << "'--swift-install-components=autolink-driver;compiler;clang-builtin-headers;stdlib;swift-remote-mirror;sdk-overlay;license'" + + cmd << "'--llvm-install-components=llvm-cov;llvm-profdata;IndexStore'" + cmd << "--install-prefix=/usr" + cmd << "--install-destdir=#{@installs}" + cmd << "--build-dir #{@builds}" execute cmd.join(" ") - execute "ls -a /usr/bin/*ld.gold" + removeLinkerSymLink() + logBuildCompleted() + end + + def prepare + removeLinkerSymLink() + execute "mkdir -p #{@builds}" + # Fix for missed file: `CMake Error at cmake/modules/SwiftSharedCMakeConfig.cmake:196 (include):` + # execute "touch \"#{@cmark.builds}/src/CMarkExports.cmake\"" + setupLinkerSymLink() + end + + def setupLinkerSymLink + if @arch == Arch.armv7a + targetFile = "/usr/bin/armv7-none-linux-androideabi-ld.gold" + puts "Making symbolic link to \"#{targetFile}\"..." + execute "sudo ln -svf #{@ndk.sources}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/arm-linux-androideabi/bin/ld.gold #{targetFile}" + execute "ls -al /usr/bin/*ld.gold" + # FIXME: Remove simlink once done. + end + end + + def removeLinkerSymLink + if @arch == Arch.armv7a + message "Removing previously created symlink..." + targetFile = "/usr/bin/armv7-none-linux-androideabi-ld.gold" + execute "sudo rm -fv #{targetFile}" + execute "ls -al /usr/bin/*ld.gold" + end end - def make() + def make prepare build end - def help - execute "cd #{Config.swiftSourcesRoot} && ./swift/utils/build-script --help | more" + def checkout + checkoutIfNeeded(@sources, "https://github.com/apple/swift.git", "8e38b67d66b41af9062627653963384db0a799eb") end - def update - execute "cd #{Config.swiftSourcesRoot} && ./swift/utils/update-checkout" + def clean + execute "rm -rf #{@builds}" + execute "rm -rf #{@installs}" end end diff --git a/Scripts/Builders/XMLBuilder.rb b/Scripts/Builders/XMLBuilder.rb new file mode 100644 index 00000000..c2bdcf47 --- /dev/null +++ b/Scripts/Builders/XMLBuilder.rb @@ -0,0 +1,59 @@ +require_relative "../Common/Builder.rb" + +class XMLBuilder < Builder + + def initialize(arch = Arch.default) + super(Lib.xml, arch) + end + + def checkout + checkoutIfNeeded(@sources, "https://github.com/GNOME/libxml2.git") + end + + def prepare + execute "mkdir -p #{@build}" + end + + def configure + # Arguments took from `swift/swift-corelibs-foundation/build-android` + ndkToolchainPath = "#{Config.ndkInstallRoot}/#{@target}" + ndkToolchainBinPath = "#{ndkToolchainPath}/bin" + ndkToolchainSysPath = "#{ndkToolchainPath}/sysroot" + archFlags = "-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16" + ldFlags = "-march=armv7-a -Wl,--fix-cortex-a8" + cmd = ["cd #{@sourcesDir} &&"] + cmd << "PATH=#{ndkToolchainBinPath}:$PATH" + cmd << "CC=#{ndkToolchainBinPath}/arm-linux-androideabi-clang" + cmd << "CXX=#{ndkToolchainBinPath}/arm-linux-androideabi-clang++" + cmd << "AR=#{ndkToolchainBinPath}/arm-linux-androideabi-ar" + cmd << "AS=#{ndkToolchainBinPath}/arm-linux-androideabi-as" + cmd << "LD=#{ndkToolchainBinPath}/arm-linux-androideabi-ld" + cmd << "RANLIB=#{ndkToolchainBinPath}/arm-linux-androideabi-ranlib" + cmd << "NM=#{ndkToolchainBinPath}/arm-linux-androideabi-nm" + cmd << "STRIP=#{ndkToolchainBinPath}/arm-linux-androideabi-strip" + cmd << "CHOST=arm-linux-androideabi" + cmd << "CPPFLAGS=\"#{archFlags} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing\"" + cmd << "CXXFLAGS=\"#{archFlags} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -frtti -fexceptions -std=c++11 -Wno-error=unused-command-line-argument\"" + cmd << "CFLAGS=\"#{archFlags} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing\"" + cmd << "LDFLAGS=\"#{ldFlags}\"" + + execute cmd.join(" ") + " autoreconf -i" + + args = "--with-sysroot=#{ndkToolchainSysPath} --with-zlib=#{ndkToolchainSysPath}/usr --prefix=#{@installDir} --host=arm-linux-androideabi --without-lzma --disable-static --enable-shared --without-http --without-html --without-ftp" + execute cmd.join(" ") + " ./configure " + args + end + + def build + execute "cd #{@sourcesDir} && make libxml2.la" + execute "cd #{@sourcesDir} && make install-libLTLIBRARIES" + execute "cd #{@sourcesDir}/include && make install" + end + + def make + checkout + prepare + configure + build + end + +end diff --git a/Scripts/Common/Arch.rb b/Scripts/Common/Arch.rb new file mode 100644 index 00000000..4de753bc --- /dev/null +++ b/Scripts/Common/Arch.rb @@ -0,0 +1,23 @@ +class Arch + + def self.default + return armv7a + end + + def self.host + return "host" + end + + def self.x86 + return "x86" + end + + def self.armv7a + return "armv7a" + end + + def self.aarch64 + return "aarch64" + end + +end diff --git a/Scripts/Common/Builder.rb b/Scripts/Common/Builder.rb new file mode 100755 index 00000000..aec74477 --- /dev/null +++ b/Scripts/Common/Builder.rb @@ -0,0 +1,64 @@ +require_relative "Tool.rb" +require_relative "Lib.rb" +require_relative "Arch.rb" +require_relative "Config.rb" +require_relative "Location.rb" +require_relative "Downloader.rb" + +class Builder < Tool + + attr_reader :builds, :installs, :sources + + def initialize(component, arch) + @component = component + @arch = arch + @sources = "#{Config.sources}/#{component}" + @patches = "#{Config.patches}/#{component}" + @builds = "#{Config.build}/#{arch}/#{component}" + @installs = "#{Config.install}/#{arch}/#{component}" + end + + def lib + return @installs + "/lib" + end + + def bin + return @installs + "/bin" + end + + def include + return @installs + "/include" + end + + def usr + return @installs + "/usr" + end + + def logBuildCompleted + message "\"#{@component}\" build is completed." + end + + def logConfigureCompleted + message "\"#{@component}\" configuring is completed." + end + + def logInstallCompleted + message "\"#{@component}\" install is completed." + end + + def checkoutIfNeeded(localPath, repoURL, revision) + if File.exist?(localPath) + message "Repository \"#{repoURL}\" seems already checked out to \"#{localPath}\"." + else + execute "mkdir -p \"#{localPath}\"" + # Checking out specific SHA - https://stackoverflow.com/a/43136160/1418981 + execute "cd \"#{localPath}\" && git init && git remote add origin \"#{repoURL}\"" + execute "cd \"#{localPath}\" && git config --local uploadpack.allowReachableSHA1InWant true" + execute "cd \"#{localPath}\" && git fetch --depth 10 origin #{revision}" + # Disable warning about detached HEAD - https://stackoverflow.com/a/45652159/1418981 + execute "cd \"#{localPath}\" && git -c advice.detachedHead=false checkout FETCH_HEAD" + message "#{repoURL} checkout to \"#{localPath}\" is completed." + end + end + +end diff --git a/Scripts/Common/Config.rb b/Scripts/Common/Config.rb index 7dee2ab5..f90cf6d1 100755 --- a/Scripts/Common/Config.rb +++ b/Scripts/Common/Config.rb @@ -1,58 +1,33 @@ -class Config - - def self.androidAPI - return "21" - end - - def self.verify - puts "- Android NDK Path: \t\"#{andkPath}\"" - puts "- ICU Sources Path: \t\"#{icuSources}\"" - puts "- ICU Patches Path: \t\"#{icuPatchesDirPath}\"" - puts "- Swift Sources Path: \t\"#{swiftSources}\"" - puts "- Build root Path: \t\"#{buildRoot}\"" - puts "- Install root Path: \t\"#{installRoot}\"" - end +require_relative "Location.rb" - def self.ndkSourcesRoot - return getEnvVariable('SA_SOURCES_ROOT_ANDK') - end - - def self.icuSourcesRoot - return getEnvVariable('SA_SOURCES_ROOT_ICU') - end +class Config - def self.swiftSourcesRoot - return getEnvVariable('SA_SOURCES_ROOT_SWIFT') + def self.root + return File.realpath(File.dirname(__FILE__) + "/../../") end - def self.buildRoot - return getEnvVariable('SA_BUILD_ROOT') + def self.sources + return "#{root}/#{Location.sources}" end - def self.swiftBuildRoot - return getEnvVariable('SA_BUILD_ROOT_SWIFT') + def self.downloads + return "#{root}/#{Location.downloads}" end - def self.installRoot - return getEnvVariable('SA_INSTALL_ROOT') + def self.build + return "#{root}/#{Location.build}" end - def self.icuPatchesRoot - return getEnvVariable('SA_PATCHES_ROOT_ICU') + def self.install + return "#{root}/#{Location.install}" end - def self.projectsRoot - return getEnvVariable('SA_PROJECTS_ROOT') + def self.patches + return "#{root}/#{Location.patches}" end - def self.getEnvVariable(name) - result = ENV[name] - if result.nil? - puts "Environment variable \"#{name}\" is not found. Did you completed Vagrant setup?" - puts "Check \"config.vm.provision\" setting in Vagrantfile..." - abort - end - return result + def self.projects + return "#{root}/#{Location.projects}" end end diff --git a/Scripts/Common/Downloader.rb b/Scripts/Common/Downloader.rb new file mode 100644 index 00000000..82fb4ae2 --- /dev/null +++ b/Scripts/Common/Downloader.rb @@ -0,0 +1,58 @@ +require_relative "Tool.rb" + +class Downloader < Tool + + def initialize(downloadsDirPath, destinationDirPath, url, downloadedFileNameMask) + @downloads = downloadsDirPath + @destination = destinationDirPath + @url = url + @fileNameMask = downloadedFileNameMask + end + + def bootstrap() + downloadIfNeeded() + unpackIfNeeded() + end + + def unpack() + if archive.end_with? ".tar.gz" + execute "cd #{@downloads} && tar -xzf \"#{archive}\"" + elsif archive.end_with? ".zip" + execute "cd #{@downloads} && unzip -q -o \"#{archive}\"" + else + raise "Don't know how to unpack file \"#{archive}\"." + end + unpackedDir = Dir[@downloads + "/" + @fileNameMask].select { |dir| File.directory?(dir) }.first + if !unpackedDir.nil? + File.rename(unpackedDir, @destination) + end + end + + def unpackIfNeeded() + if File.exist?(@destination) + message "Seems URL \"#{@url}\" already downloaded and unpacked to \"#{@destination}\"." + return + end + unpack() + end + + def download() + execute "cd \"#{@downloads}\" && curl -O -J -L #{@url}" + end + + def downloadIfNeeded() + if !archive.nil? + message "Seems URL \"#{@url}\" already downloaded to \"#{archive}\"." + return + end + download() + end + + def archive + if @archive.nil? + @archive = Dir[@downloads + "/" + @fileNameMask].select { |file| !File.directory?(file) }.first + end + return @archive + end + +end diff --git a/Scripts/Common/Lib.rb b/Scripts/Common/Lib.rb new file mode 100644 index 00000000..f268299c --- /dev/null +++ b/Scripts/Common/Lib.rb @@ -0,0 +1,47 @@ +class Lib + + def self.swift + return "swift" + end + + def self.icu + return "icu" + end + + def self.ndk + return "ndk" + end + + def self.llvm + return "llvm" + end + + def self.cmark + return "cmark" + end + + def self.clang + return "clang" + end + + def self.crt + return "compiler-rt" + end + + def self.curl + return "curl" + end + + def self.xml + return "xml" + end + + def self.dispatch + return "swift-corelibs-libdispatch" + end + + def self.foundation + return "swift-corelibs-foundation" + end + +end diff --git a/Scripts/Common/Location.rb b/Scripts/Common/Location.rb new file mode 100644 index 00000000..6b251fc3 --- /dev/null +++ b/Scripts/Common/Location.rb @@ -0,0 +1,27 @@ +class Location + + def self.sources + return "Sources" + end + + def self.install + return "Install" + end + + def self.build + return "Build" + end + + def self.downloads + return "Downloads" + end + + def self.patches + return "Patches" + end + + def self.projects + return "Projects" + end + +end diff --git a/Scripts/Common/Tool.rb b/Scripts/Common/Tool.rb index 0999277a..1d62f308 100755 --- a/Scripts/Common/Tool.rb +++ b/Scripts/Common/Tool.rb @@ -5,11 +5,20 @@ class Tool def execute(command) puts "\e[32m#{command}\e[0m" # Print to console with Green color. - system command + if system(command) != true + message "Execution of command is failed:" + error command + puts + raise + end end def message(command) puts "\e[36m#{command}\e[0m" # Print to console with Light blue color. end + def error(command) + puts "\e[31m#{command}\e[0m" # Print to console with Red color. + end + end diff --git a/Scripts/HelloProjectBuilder.rb b/Scripts/HelloProjectBuilder.rb deleted file mode 100755 index bbeff80c..00000000 --- a/Scripts/HelloProjectBuilder.rb +++ /dev/null @@ -1,38 +0,0 @@ -require_relative "Builders/Builder.rb" -require_relative "Common/Config.rb" - -# See: -# - Build error: No such module "SwiftGlibc" – https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20160919/002955.html -class HelloProjectBuilder < Builder - - def initialize() - super() - @buildDir = Config.buildRoot + "/hello" - @executablePath = @buildDir + "/hello" - @projectRoot = "#{Config.projectsRoot}/Hello" - end - - def build - cmd = ["cd #{@buildDir} &&"] - cmd << "PATH=#{Config.swiftBuildRoot}/swift-linux-x86_64/bin:$PATH" - cmd << "swiftc" - cmd << "-tools-directory #{Config.ndkSourcesRoot}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/arm-linux-androideabi/bin" - cmd << "-target armv7-none-linux-androideabi" # Targeting android-armv7. - cmd << "-sdk #{Config.ndkSourcesRoot}/platforms/android-#{Config.androidAPI}/arch-arm" # Use the same NDK path and API version as you used to build the stdlib in the previous step. - cmd << "-L #{Config.ndkSourcesRoot}/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a" # Link the Android NDK's libc++ and libgcc. - cmd << "-L #{Config.ndkSourcesRoot}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x" - cmd << "#{@projectRoot}/hello.swift" - execute cmd.join(" ") - execute "readelf -h #{@executablePath}" - end - - def prepare() - execute "mkdir -p #{@buildDir}" - end - - def make - prepare - build - end - -end diff --git a/Scripts/Shell/bootstrap.sh b/Scripts/Shell/bootstrap.sh index fe760887..fc9cfe9a 100755 --- a/Scripts/Shell/bootstrap.sh +++ b/Scripts/Shell/bootstrap.sh @@ -1,14 +1,16 @@ #!/bin/bash echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -SA_CMD="sudo apt-get update" +SA_CMD="apt-get -y update" echo "Executing command: \"$SA_CMD\"" echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" $SA_CMD # Swift dependencies echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -SA_CMD="sudo apt-get install ruby cmake ninja-build clang python uuid-dev libicu-dev icu-devtools libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config libblocksruntime-dev libcurl4-openssl-dev systemtap-sdt-dev tzdata rsync libz3-dev" +# Z3 dependency (`apt-get install libz3-dev`) temporary removed due compile error `llvm::Twine(Z3_get_error_msg(Context, Error)));` +# See: https://reviews.llvm.org/D54391 +SA_CMD="apt-get -y install mc ruby cmake ninja-build clang python autoconf libtool uuid-dev libicu-dev icu-devtools libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config libblocksruntime-dev libcurl4-openssl-dev systemtap-sdt-dev tzdata rsync" echo "Executing command: \"$SA_CMD\"" echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" $SA_CMD @@ -20,4 +22,12 @@ echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" ruby --version rake --version echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" +echo "Ubuntu version" +echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" +lsb_release -irc +echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" +echo "Synched folder Contents" +echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" +ls -l /vagrant +echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" echo "Done!" diff --git a/Scripts/Shell/environment.sh b/Scripts/Shell/environment.sh index 69bdaee3..989bc567 100644 --- a/Scripts/Shell/environment.sh +++ b/Scripts/Shell/environment.sh @@ -1,33 +1 @@ -## Sources -export SA_SOURCES_ROOT=/vagrant/Sources - -export SA_SOURCES_ROOT_ANDK=$SA_SOURCES_ROOT/android-ndk-r18b -export SA_SOURCES_ROOT_ICU=$SA_SOURCES_ROOT/icu -export SA_SOURCES_ROOT_SWIFT=$SA_SOURCES_ROOT/swift - -## Build -export SA_BUILD_ROOT=/vagrant/Build - -export SA_BUILD_ROOT_ANDK=$SA_BUILD_ROOT/android-ndk -export SA_BUILD_ROOT_ICU=$SA_BUILD_ROOT/icu -export SA_BUILD_ROOT_SWIFT=$SA_BUILD_ROOT/swift-android - -## Install -export SA_INSTALL_ROOT=/vagrant/Install - -export SA_INSTALL_ROOT_ANDK=$SA_INSTALL_ROOT/android-ndk -export SA_INSTALL_ROOT_ICU=$SA_INSTALL_ROOT/icu -export SA_INSTALL_ROOT_SWIFT=$SA_INSTALL_ROOT/swift - -## Patches -export SA_PATCHES_ROOT=/vagrant/Patches - -export SA_PATCHES_ROOT_ICU=$SA_PATCHES_ROOT/icu - -## Projects -export SA_PROJECTS_ROOT=/vagrant/Projects - - -## Misc -export PATH=$PATH:$SA_SOURCES_ROOT_ANDK export RUBYOPT=-W0 diff --git a/Sources/.gitignore b/Sources/.gitignore index e385402b..6ec84a6b 100644 --- a/Sources/.gitignore +++ b/Sources/.gitignore @@ -1,3 +1,4 @@ /*/ /*.zip /*.tgz +/*.tar.gz diff --git a/Sources/Readme.md b/Sources/Readme.md index 27b63635..24eb86ee 100644 --- a/Sources/Readme.md +++ b/Sources/Readme.md @@ -1 +1 @@ -# Put downloaded Swift, ICU sources and Android NDK here +# Swift, ICU, libXML, ... sources and Android NDK will be extracted here. diff --git a/VERSION b/VERSION index 3eefcb9d..7dea76ed 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +1.0.1 diff --git a/Vagrantfile b/Vagrantfile index d0cf9864..c9fd7e9a 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,12 +1,16 @@ # -*- mode: ruby -*- # vi: set ft=ruby : +# See: +# - https://github.com/readdle/swift-android-toolchain/blob/master/vagrant/Vagrantfile Vagrant.configure("2") do |config| + config.vm.box = "ubuntu/bionic64" + config.vm.provision :shell, path: "Scripts/Shell/bootstrap.sh" config.vm.provision :shell, inline: "echo 'source /vagrant/Scripts/Shell/environment.sh' > /etc/profile.d/sa-environment.sh", :run => 'always' config.vm.provider "virtualbox" do |vb| vb.memory = "5120" # Setting value less that `5120` can cause linker to fail. - vb.cpus = "4" # Setting value less that `4` can cause sloooooow compile time. + vb.cpus = `sysctl -n hw.physicalcpu`.to_i # use all available end end