title:Linux Hello world in Swift keywords:linux,swift,apple,c,sdl2 # Linux Hello world in Swift ## Intro Swift is one of cool modern languages, that appeared recently on the scene. Purpose of Swift is replace C/ObjectC/C++ on MacOS. In same time its works on Linux. Support of Swift for Linux is not that great there is lack of many libraries and all Siwft power opens on Macos, but its still some fun language to play. Main swift page provides only Macos and Ubuntu as main supported platforms. Anything else you may have troubles to get working. Currently supported architectures are intel64 and arm64. Lets get into this journey of running Swift on Linux. ## Installing Swift ### Ubuntu Installing on Ubuntu is most easiest part, download from main page and done. [https://swift.org/download/](https://swift.org/download/) ```bash wget -c https://swift.org/builds/swift-5.1.4-release/ubuntu1804/swift-5.1.4-RELEASE/swift-5.1.4-RELEASE-ubuntu18.04.tar.gz tar -xvf swift-5.1.4-RELEASE-ubuntu18.04.tar.gz ``` ### Archlinux Installing from main swift page, not able to compile because of missing GCC flags. So easiest way to install is from AUR [https://aur.archlinux.org/packages/swift-bin/](https://aur.archlinux.org/packages/swift-bin/) Compiling other swift package from AUR have same issues, related to not able to compile source. ```bash wget -c https://aur.archlinux.org/cgit/aur.git/snapshot/swift-bin.tar.gz tar -xvf swift-bin.tar.gz cd siwft-bin makepkg sudo pacman -U ``` ## Compile Swift All this examples given for Swift version 5.1 ```bash mkdir HelloWorld cd ./HelloWorld/ swift package init --type executable swift run ``` Compiled file is located in ```bash ./.build/debug/HelloWorld ``` ## Static Swift Compilation Swift static compilation compiles in all Swift runtime and uses default Linux libraries. ```bash swift build -c release -Xswiftc -static-stdlib ``` File is located in ./.build/x86_64-unknown-linux/release/HelloWorld ```bash ls -lah ./.build/x86_64-unknown-linux/release/HelloWorld -rwxr-xr-x 1 fam fam 34M Mar 1 18:29 ./.build/x86_64-unknown-linux/release/HelloWorld ldd ./.build/x86_64-unknown-linux/release/HelloWorld linux-vdso.so.1 (0x00007ffebcd17000) libdl.so.2 => /usr/lib/libdl.so.2 (0x00007efc5a6d4000) libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007efc5a6b2000) libatomic.so.1 => /usr/lib/libatomic.so.1 (0x00007efc5a6a8000) libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007efc5a4bf000) libm.so.6 => /usr/lib/libm.so.6 (0x00007efc5a379000) libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007efc5a35f000) libc.so.6 => /usr/lib/libc.so.6 (0x00007efc5a197000) /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007efc5c624000) ``` ## Swift on ARM64 Swift installation manual for RasPi4 [https://swift-arm.com/install-swift/](https://swift-arm.com/install-swift/) ```bash curl -s https://packagecloud.io/install/repositories/swift-arm/release/script.deb.sh | sudo bash sudo apt-get install swift5 ``` Now steps from beginning could be followed. And result will be same. ## Interfacing to C Swift is based on clang/llvm and able to parse C language and create interface to Swift. Its eliminates need to write glue/binding library for Swift and simplifies C integration. ```bash mkdir Cint0 cd Cint0 swift package init --type executable ``` Define C header with functions to be binded _code.h_ ```c #ifndef __CCODE_H #define __CCODE_H #include #include int one(); int two(); int calc(int a, int b); #endif ``` Function implementation _code.c_ ```c #include "include/code.h" int one() { printf("First\n"); return 1; } int two() { printf("Second\n"); return 2; } int calc(int a, int b) { return a+b; } ``` _main.swift_ ```swift import ccode; print("Start program") print(one()); print(ccode.two()); print(calc(12,12)) print("End program") ``` C source and header files are ready. Swift code that using C code is written. So its time to define package and build everything. Package.swift defines what is included in source and dependencies. So add target "Cint0" with dependencies on "ccode" that is our C code. And then add extra target that will compile code "ccode" and doesn't depend on anything. ... and build. _Package.swift_ ```swift // swift-tools-version:5.1 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Cint0", dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name:"Cint0", dependencies: ["ccode"]), .testTarget( name: "Cint0Tests", dependencies: ["Cint0"]), .target( name:"ccode", dependencies: []), ] ) ``` ## SDL2 example ### Binding SDL2 library To use C SDL2 headers from Swift we need to create bindings. This also shows how to bind C code to Swift ```bash mkdir CSDL2 cd CSDL2 swift package init --type system-module ``` Resulting files are ``` $ swift package init --type system-module Creating system-module package: CSDL2 Creating Package.swift Creating README.md Creating .gitignore Creating module.modulemap ``` Create __Headers__ directory and add there file _CSDL2-Header.h_ ```c #include ``` _Package.swift_ ```swift // swift-tools-version:5.1 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "CSDL2", products: [ // Products define the executables and libraries produced by a package, and make them visible to other packages. .library( name: "CSDL2", targets: ["CSDL2"]), ], dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name: "CSDL2", dependencies: []), .testTarget( name: "CSDL2Tests", dependencies: ["CSDL2"]), ] ) ``` Here is main thing, to tell Swift with headers to make accessible _module.modulemap_ ``` module CSDL2 { header "Headers/CSDL2-Header.h" link "SDL2" export * } ``` Now its time to test CSDL2 package ### SDL2 test with bindings SDL2 test ```bash mkdir SDLtest cd ./SDLtest swift package init --type executable ``` Small SDL2 example in C ```c #include #define SCREEN_WIDTH 200 #define SCREEN_HEIGHT 200 char quit = 0; SDL_Window *window = NULL; SDL_Renderer *renderer = NULL; int main() { SDL_Init(SDL_INIT_VIDEO); window = SDL_CreateWindow( "WEBASM", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL); renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, 0xff); int quit=0; while(0 == quit) { SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: { quit = 1; break; } } } } SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); } ``` Lets convert C example to working with Swift code Pointers can be defined as OpaquePointer without type so far. All functions are called same as in C. Enum types if they are passed then can be accessed as NAME.rawValue . ```swift import CSDL2 var windowPtr: OpaquePointer! = nil var renderPtr: OpaquePointer! = nil SDL_Init(0) SDL_CreateWindowAndRenderer(200,200,0,&windowPtr,&renderPtr) SDL_SetRenderDrawColor(renderPtr,0xff,0xff,0xff,0xff) var quit = 0; var e = SDL_Event(); while quit == 0 { while SDL_PollEvent(&e) != 0 { switch e.type { case case SDL_QUIT.rawValue:: quit = 1 default: print("Unknown event") } } } print("Hello, world!") SDL_DestroyRenderer(renderPtr) SDL_DestroyWindow(windowPtr) SDL_Quit() ``` So far all Swift features looks like they are working out of the box, without deep Swift knowledge was able to bind library, and use it. Also this is largest code base of Swift code that I ever wrote in my life. So far it looks like easy language to learn. ## Sources ## Links [01] [https://www.programiz.com/swift-programming](https://www.programiz.com/swift-programming) [02] [https://swift.org/download/](https://swift.org/download/) [03] [https://aur.archlinux.org/packages/swift-bin/](https://aur.archlinux.org/packages/swift-bin/) [04] [https://swift-arm.com/install-swift/](https://swift-arm.com/install-swift/) [05] [https://github.com/apple/swift-package-manager/blob/master/Documentation/Usage.md](https://github.com/apple/swift-package-manager/blob/master/Documentation/Usage.md) [06] [https://theswiftdev.com/how-to-call-c-code-from-swift/](https://theswiftdev.com/how-to-call-c-code-from-swift/) [07] [https://github.com/KevinVitale/SwiftSDL/blob/master/Package.swift](https://github.com/KevinVitale/SwiftSDL/blob/master/Package.swift) [08] [https://rderik.com/blog/making-a-c-library-available-in-swift-using-the-swift-package/](https://rderik.com/blog/making-a-c-library-available-in-swift-using-the-swift-package/) [09] [https://github.com/KevinVitale/SwiftSDL/tree/master/Sources](https://github.com/KevinVitale/SwiftSDL/tree/master/Sources) [10] [https://www.uraimo.com/2016/04/07/swift-and-c-everything-you-need-to-know/#working-with-pointers](https://www.uraimo.com/2016/04/07/swift-and-c-everything-you-need-to-know/#working-with-pointers) [11] [https://www.objc.io/blog/2018/01/30/opaque-vs-unsafe-pointers/](https://www.objc.io/blog/2018/01/30/opaque-vs-unsafe-pointers/)