summaryrefslogtreecommitdiffstats
path: root/md/writeup/linux_hello_world_in_swift.md
blob: 1b15abc6e638a40f4b05cc28d8bb58194d091236 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
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 <stdlib.h>
#include <stdio.h>

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 <SDL2/SDL.h>
```

_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 <SDL2/SDL.h>

#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/)