Сравнение Swift vs Kotlin

 
   

Небольшая табличка сравнения кода на Swift и кода на Kotlin для справки. Этакий cheet sheet.

Переменные и константы

Swift

let a: Int = 10
var b: Int = 20

Kotlin

val a: Int = 10
var b: Int = 20

Optionals

Swift

let some: Something? = nil
var some: Something? = Something(text: "Hello")

// optional chaining
let greeting = some?.greet()

// elvis
let value = some?.value ?? 30

// optional unwraping
if let some = some {
    print(some) // some is not optional
}

// force unwraping
let forced = some!

Kotlin

val some: Something? = nil
var some: Something? = Something("Hello")

// optional chaining
val greeting = some?.greet()

// elvis
val value = some?.value ?: 30

// optional unwraping
some?.let { some -> // it if name is not provided
    print(some) // some is not optional
}
if (some != null) {
    print(some) // some is smart casted and not optional
}

// force unwraping
val forced = some!!

Форматирование кода

Скобки (круглые и фигурные)

Swift

  • Круглые - не обязательны
  • Фигурные - обязательны
let str = "Hello, Swift"

func increse(_ value: Int) -> Int {
    return value + 1
}

func statements() {
    var i = 0
    while i < 10 {
        i = increase(i)
        if str == "something" {
            print(str)
        }
    }
}

Kotlin

  • Круглые - обязательны
  • Фигурные - не обязательны
val str = "Hello, Kotlin"

fun increase(value: Int): Int = value + 1

fun statements() {
    var i = 0
    while (i < 10) i = increase(i)
    if (str == "something") print(str)
}

Управляющие конструкции

Pattern Matching

Swift

let number = 42
switch number {
    case 0...7, 8, 9: print("1 digit")
    case 10: print("2 digits")
    case 11...99: print("2 digits")
    case 100...999: print("3 digits")
    default: print("4 or more digits")
}

Kotlin

val number = 42
when (number) {
    in 0..7, 8, 9 -> println("1 digit")
    10 -> println("2 digits")
    in 11..99 -> println("2 digits")
    in 100..999 -> println("3 digits")
    else -> println("4 or more digits")
}

if, when = expressions, not statements (!)

Swift

  • Не применимо

Kotlin

val test = if (true) "Test" else "False"

val state = State.Off
fun decide() = when(state) {
    State.Off -> "Off"
    State.On -> "On"
}
val decision = decide()

Типы

Любой тип

Swift

let a: Any = "Hello"
let b: AnyObject = SomeClass()

Kotlin

val a: Any = "Hello"
// no AnyObject yet

Строковая интерполяция

Swift

let str = "Hello \(nickname)"
let str2 = "Hello \(user.nickname)"

Kotlin

val str = "Hello $nickname"
val str2 = "Hello ${user.nickname}"

Интервалы (Ranges)

Swift

let rng1 = 0...10
let rng2 = 0..<10

Kotlin

val rng1 = 0..10
// no rng2

Коллекции

Swift

let stringArray = [String]()
// no stringList
let stringFloatMap = [String: Float]()
let stringSet = Set<String>()

var countries: [String] = ["Switzerland", "France", "Germany"]
countries.append("Italy")
countries.remove("France")

var jobs: [String: String] = [
    "Roger": "CEO",
    "Martin": "CTO"
]
jobs["Adrian"] = "Writer"

Kotlin

  • Нельзя использовать [] для инициализации массива, используется arrayOf
  • в arrayOf добавлять и удалять элементы нельзя, можно только их менять
val stringArray = arrayOf<String>()
val stringList = listOf<String>()
val stringFloatMap = mapOf<String, Float>()
val stringSet = setOf<String>()

val countries = mutableListOf<String>("Switzerland", "France", "Germany")
countries.add("Italy")
countries.remove("France")

val jobs = mutableMapOf(
    "Roger" to "CEO",
    "Martin" to "CTO"
)
jobs["Adrian"] = "Writer"

Итерирование коллекций

Swift

for str in stringArray {}
for (index, str) in stringArray.enumerated() {}
// no for str in stringList
for (str, num) in stringFloatMap {}
for str in stringSet {}

Kotlin

for (str in stringArray) {}
for (str in stringList) {}
for ((str, num) in stringFloatMap) {}
for (str in stringSet) {}

Процедурное программирование

Процедуры и функции

Swift

func method1(input: String) -> Int {
    return input.count
}

// no method2

func method3<T>(input: T) -> String {
    return String(describing: input)
}

Kotlin

fun method1(input: String): Int {
    return input.length
}

fun method2(input: String) = input.length

fun <T>method3(input: T) = input.toString()

ООП

Интерфейсы

Swift

protocol Person {
    var name: String { get set }
    
    func greet() -> String
    
    func showMoreInformation()
}

extension Person {
	func greet() -> String {
	    return "Hello! I am \(self)"
	}
}

Kotlin

interface Person {
    
    var name: String
        get set

    
    fun greet() = "Hello! I am $this"

    
    fun showMoreInformation()
}

Конструкторы

Swift

class Manager: Person {
    var backingName: String
    var staff: [Person]
    var state: State
    let isActive: Bool
    init(backingName = "": String, staff: [Person] = [], state: State = .off) {
        self.backingName = backingName
        self.staff = staff
        self.state = state
        self.isActive = true
    }

Kotlin

class Manager(private var backingName: String = "",
              private var staff: MutableList<Person> = mutableListOf<Person>(),
              var state: State = State.Off) : Person {
    private val isActive: Boolean
    init {
        isActive = true
    }
}

Data Classes (PONSO/POSS vs POJO)

Swift

struct Employee {
    let backingName: String
    let age: Int
    init(backingName: String = "", age: Int = 30) {
        self.backingName = backingName
        self.age = age
    }
}

Kotlin

data class Employee(private var backingName: String = "",
                    var age: Int = 30) : Person {

Инстанцирование объектов

Swift

let person = Employee(
    name: "Olivia", 
    age: 45
)

Kotlin

val person1 = Employee("Olivia", 45) 

val person2 = Employee().apply { 
    name = "Thomas"
    age = 56
}

Расширения классов

Swift

extension Double {
    var fahrenheit: Double {
	    (self * 9 / 5) + 32
    }
    var celsius: Double {
       (self - 32) * 5 / 9
    }
}

let temperature = Double(32.0)
let fahrenheit = temperature.fahrenheit
let celsius = fahrenheit.celsius
print("\(temperature) degrees Celsius is \(fahrenheit) degrees Fahrenheit")

Kotlin

val Double.fahrenheit: Double get() = (this * 9 / 5) + 32
val Double.celsius: Double get() = (this - 32) * 5 / 9

val temperature: Double = 32.0
val fahrenheit = temperature.fahrenheit
val celsius = fahrenheit.celsius
println("$temperature degrees Celsius is $fahrenheit degrees Fahrenheit")

Простые объекты и Singleton’ы

Swift

enum Constants {
    static let PI = 3.14
    static let ANSWER = 42
    
    static func name() -> String {
        return "Math constants"
    }
}

Kotlin

object Constants {
    val PI = 3.14
    val ANSWER = 42

    fun name() = "Math contstants"
}

Объекты-компаньоны

Swift

  • Просто используйте static (class) члены

Kotlin

  • В Kotlin нет статических членов
companion object OptionalName {
    val MAXIMUM_EMPLOYEE_COUNT = 10

    fun managerFactory() = Manager("Maria Hill")
}

Перегрузка операторов

Swift

  • Можно делать свои операторы (например квадратный корень)
func + (lhs: Person, rhs: Person) -> Team {
    return Team(lhs, rhs)
}

let team = manager + person

Kotlin

operator fun plus(person: Person): Team {
    return Team(this, person)
}

val team = manager + person

Инфиксные методы

Swift

  • Не применимо

Kotlin

infix fun addPerson(person: Person) {
    if (staff.count() < MAXIMUM_EMPLOYEE_COUNT) {
        staff.add(person)
    }
    else {
        throw Exception("Cannot add more staff members")
    }
}

manager addPerson person

Перечисления

Swift

enum State {
    case on
    case off
    
    var desc: String { ... }
    func notify() { ... }
}

Kotlin

enum class State {
    On, Off
    
    var desc: String { ... }
    func notify() = ...
}

Резюмирующая табличка

  Kotlin 1.2 Objective-C 2.0 Swift 4
Наследование Одинарное, с интерфейсами и расширениями Одинарное, с протоколами Одинарное, с протоколами и расширениями
Точки с запятой ; Не обязательны Обязательны Не обязательны
Объявление класса class @interface & @implementation class
Интерфейсы реализует interface поддерживает @protocol поддерживает protocol
Подключение кода import (символы) #import (файлы) import (символы)
Расширение классов Расширения Категории Расширения
Динамическая типизация Any id Any
Суффикс приватных полей Не используется _ (подчеркивание) _ (подчеркивание)
Управление памятью Сборка мусора (GС) Ручное или автоматическое управление памятью (MRC vs ARC) Автоматическое управление памятью (ARC)
Дженерики да (type erasure) да (type erasure) да
Указатели на метод нет @selector #selector
Обратный вызов (callbacks) Лямбды Делегаты и блоки замыкания
Указатели нет да Через библиотечные классы
Корневые классы Object NSObject / NSProxy / … NSObject / NSProxy / …
Управление областью видимости public / internal / protected / private @public / @protected / @private (только поля) open / public / internal / fileprivate / private
Обработка ошибок try / catch / finally + Exception @try / @catch / @finally + NSException do / try / catch + Error
Пространства имен Пакеты Через префиксы классов Неявные, через модули
Грамматика kotlinlang.org   developer.apple.com

Разрабатываем и отлаживаем С++ в Docker с помощью VSCode

     
 

Продолжаем цикл статей “Как кодить на С++ под OSX для Ubuntu”. После сборки cross-toolchain’ов стояла задача научиться собирать, запускать и отлаживать С++ под OSX для Linux (Ubuntu в данном случае). Как оказалось cross-toolchain был не нужен :(. Но об этом позже.

Для начала нужна была IDE, в которой можно было бы комфортно редактировать код и отлаживаться. Претенденты были такие: Xcode, Eclipse (CDT), CLion, чуть позже к ним добавился VSCode и впоследствии выиграл соревнование.

Постановка задачи была такая: C++, CMake, Linux, при этом редактирование кода и отладка должна работать под OSX.

Xcode поэтому выпал из этой гонки сразу, он есть очень удобная IDE для C++, но в целом в основном для OSX. CMake наверное завести можно, но это будет большое количество сторонних средств.

CLion выпал из этой же гонки примерно по тем же причинам (хотя он вроде умеет в CMake). Плюс я не смог в нем нормально подружиться с Docker.

Остался Eclipse CDT, в нем получилось практически все что требовалось (с cross-toolchain), завелась даже отладка через cross-gdb, однако были странные махинации чтобы нормально работать с CMake и контейнером он управлял относительно сам (не совсем прозрачно), хотя надо отметить что поддержка Docker в Eclipse плюс-минус хорошая.

После этого я пошел посерфить интеренет в поисках каких-нибудь идей, как нормально подружить Eclipse и CMake, и тут я наткнулся на VSCode. Которые не позиционирует себя как IDE, но умеет в дебаг и всякие user-defined task’и. Несмотря на мое некоторое отношение к продуктам Microsoft, я решил дать этому редактору шанс и попробовал его… и надо признать, это очень хороший инструмент.

Теперь же собственно, как завести, чтобы все работало.

Для начала нам понадобится собственно VSCode, настроенный так, как вам наиболее удобно. Можно сразу поставить расширения для работы с C++ (C/C++, Native Debug), CMake (CMake, CMake Tools), Docker.

Далее нам потребуется такая структура проекта (в принципе вы можете выбрать такую структуру, какая вам больше нравится, это скажем так рабочий пример):

.vscode
  tasks.json
  launch.json
build
CMakeLists.txt
dbuild.sh
ddebugger.sh
dmaker.sh
Dockerfile
main.cpp

Начнем с С++, пример простой, однако чтобы понять что мы действительно работаем для Linux я добавил несколько linux’овых вещей.

#include <unistd.h>
#include <limits.h>

#include <iostream>

using namespace std;

int main() {
	char hostname[HOST_NAME_MAX];
	char username[LOGIN_NAME_MAX];
	gethostname(hostname, HOST_NAME_MAX);
	getlogin_r(username, LOGIN_NAME_MAX);

	cout << "hostname: " << hostname << ", login: " << username << endl; // prints Hello World!
	return 0;
}

Этот код мы будем собирать, запускать и отлаживать.

Далее CMakeLists.txt, который тоже простой и относительно шаблонный:

cmake_minimum_required(VERSION 3.5)

project(HWord)

set(HWORD_VERSION_MAJOR 1)
set(HWORD_VERSION_MINOR 0)

set(SOURCE ${PROJECT_SOURCE_DIR}/main.cpp)

add_executable(${PROJECT_NAME} ${SOURCE})

Собираем

Как я уже выше писал сначала я пытался собрать все это безобразие под OSX с помощью cross-toolchain. Это плюс-минус работало, но часто приходилось пересобирать toolchain с еще каким-нибудь волшебным флагом, а на моем машине это делается примерно 3 часа. В одну из таких пересборок мне пришла мысль, а почему бы не собирать docker’ом, т.е. gcc который в контейнере и в требуемой системе (linux).

Таким образом собираем такой контейнер:

Dockerfile

FROM ubuntu:16.04

RUN apt-get update 
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y gcc g++ gdb cmake

WORKDIR /opt/build
VOLUME ["/opt"]

Для упрощения работы с командной строкой docker’а заведем пару скриптов:

Скрипт сборки образа:

dbuild.sh

#!/bin/bash

cwd=$(pwd)

docker build \
    -t mrdekk/maker \
    .

Ничего сверхординарного, но возможно вам лучше поставить свой тег, вместо mrdekk/maker сделать %username%/maker

Скрипт запуска сборок:

dmaker.sh

#!/bin/bash

cwd=$(pwd)

docker stop maker
docker rm maker
docker run \
	-it \
	--name maker \
	-p 6666:6666 \
	-v ${cwd}:/opt \
	--privileged \
	mrdekk/maker \
    "${@}" 

Скрипт запуска контейнера для отладки:

ddebugger.sh

#!/bin/bash

cwd=$(pwd)

docker stop maker
docker rm maker
docker run \
	-dt \
	--name maker \
	-p 6666:6666 \
	-v ${cwd}:/opt \
	--privileged \
	mrdekk/maker \
    "${@}" 

Скрипты запуска сборки и дебаггера в общем отличаются только ключами -it и -dt.

Теперь сделаем несколько задач (tasks) для VSCode

Задача сборки контейнера:

Ничего особенного, вызываем скрипт dbuild.sh

{
    "label": "Docker: Build Containers",
    "command": "${workspaceFolder}/dbuild.sh",
},

И заодно выполняем ее, после этого можете сделать docker images и проверить, что образ mrdekk/maker появился

Задача для CMake:

Теперь с помощью CMake сгенерим Makefile’ы для сборки проекта. Здесь мы воспользуемся скриптом dmaker.sh, но будем вызывать его с набором ключей:

{
    "label": "CMake: Initialize",
    "command": "${workspaceFolder}/dmaker.sh",
    "args": [
        "cmake", "-G", "'Unix Makefiles'", "-DCMAKE_BUILD_TYPE=Debug", "/opt"
    ],
    "options": {
        "cwd": "${workspaceFolder}"
    }
},

/opt это путь до Volume’а в контейнере в который мы будем проецировать текущую папку с исходниками проекта - это в общем часть магии.

После этого в подпапке build вы должны увидеть сгенерированные cmake’ом файлы.

Задача для сборки бинарника:

Здесь снова используем скрипт dmaker.sh но с другими ключами

{
    "label": "Make: Build Project",
    "command": "${workspaceFolder}/dmaker.sh",
    "args": [
        "make", "-j", "8"
    ],
    "options": {
        "cwd": "${workspaceFolder}"
    },
    "group": {
        "kind": "build",
        "isDefault": true
    }
},

После того, как собереться можете попробовать сделать так ./build/HWord на OSX, и вы должны получить примерно такое:

exec format error: ./build/HWord

Это правильно, наш бинарник собран для linux и на OSX запускаться не должен. Если же вы увидите вывод программы, это значит что что-то пошло не так (вы собрали OSX’овым компилятором).

Запускаем без отладки

Теперь у нас есть бинарник, надо проверить что он запускается. Для этого снова воспользуемся скриптом dmaker.sh и такой задачей:

{
    "label": "Docker: Run Containers",
    "command": "${workspaceFolder}/dmaker.sh",
    "args": [
        "/opt/build/HWord"
    ]
},

После этого вы должны увидеть в docker logs maker и терминале VSCode примерно такое

hostname: 03a3a4dee13f, login:

Это хорошо, наш бинарник на linux работает хорошо.

Отлаживаемся

С помощью VSCode поставьте breakpoint куда-нибудь в коде. Нам будет необходим запущенный в фоне контейнер, внутри которого мы через docker exec будем запускать gdb. Увы, завести VSCode так, чтобы он смог нормально в интерактивном режиме (dmaker.sh и -it) запускать debugger у меня не получилось (видимо механизм запуска дебаггера в VSCode как-то так хитро устроен), поэтому я воспользовался pipeTransport и все заработало.

Таким образом задача для предварительного запуска контейнера:

{
    "label": "Docker: Run Debugging Container",
    "command": "${workspaceFolder}/ddebugger.sh",
    "args": [
        "bash"
    ]
}

а launch.json выглядит так

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Container Debug",
            "type": "cppdbg",
            "request": "launch",
            "program": "/opt/build/HWord",
            "cwd": "/opt",
            "linux": {
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ]
            },
            "osx": {
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ]
            },
            // "preLaunchTask": "Docker: Run Debugging Container",
            "pipeTransport": {
                "pipeProgram": "docker",
                "pipeCwd": "${workspaceRoot}",
                "pipeArgs": [
                    "exec", "-i", "maker", "sh", "-c"
                ],
                "quoteArgs": false,
                "debuggerPath": "/usr/bin/gdb"
            },
            "sourceFileMap": {
                "/opt":"${workspaceFolder}"
            },
        }
    ]
}

Внимательно ко всем параметрам, они все имеют значение.

После этого жмем F5 (или в меню выбираем Start Debugging) и… отлаживаемся. Дебаггер должен остановить выполнение в установленном вами breakpoint’е.

Примеры кода и исходники к статье лежат тут mrdekk/viscose-cpp-docker.

P.S. Да, я тоже ненавижу автокомплит, когда он что-то исправляет. В названии репозитория должно было быть vscode-cpp-docker, а получилось viscose-cpp-docker. Но, ладно! Так тому и быть.

Собираем toolchain для С++ разработки под Linux (Ubuntu) на OSX

 
     
 

Crosstool-NG

Для начала нам необходимо crosstool-ng для сборки toolchain’а для компиляции под Linux на базе OSX.

Case Sensitive Volume

Для установки crosstool-ng и для сборки правильного toolchain’а необходим Case-Sensitive Volume. Для этого воспользуемся замечательным скриптом. Опционально надо поправить в нем ${HOME} на то, куда вы реально хотите сохранять образ - у меня например второй большой диск (HDD против SSD) для всякого такого, поэтому пришлось поправить это дело.

Заодно сделаем его, воспользовавшись скриптом

./casesafe.sh create
./casesafe.sh mount

После того как станет ненужным, не забудте сделать

./casesafe.sh unmount

Установка требуемых зависимостей через HomeBrew

brew install autoconf
brew install binutils
brew install gawk
brew install gmp
brew install gnu-sed
brew install help2man
brew install mpfr
brew install openssl
brew install pcre
brew install readline
brew install wget
brew install xz

Иногда brew может сказать что зависимость уже стоит, но устарела, тогда опционально можно сделать brew update …

Еще опционально просят поставить dupes/grep ввиду того, что libc результирующего toolchain’а будет неправильно сконфигурирована, ввиду отличия макового BSD grep от GNU grep. –with-default-names необходимо чтобы системный grep заменился новым, так как без этого параметры brew’шный grep поставиться как ggrep.

brew install grep --with-default-names

Установка собственно crosstool-ng

Я решил пойти по Hacker’s way и сделать все через исходники, а не через release tarballs. Поэтому первое что делаем - клонируем репу, нужен гит:

git clone https://github.com/crosstool-ng/crosstool-ng

Далее нам требуется выбрать конкретный релиз, релизы обозначены тегами, поэтому выгребем теги и зачекаутим нужный:

git fetch --all --tags --prune
git checkout tags/crosstool-ng-1.23.0 -b r1.23.0

Далее начинаем работу по сборке. Так как мы решили пойти Hacker’s Way, то будем запускать это дело из исходников (поэтому ./configure –enable-local).

./bootstrap
./configure --enable-local
make

Для проверки успешности сборки в текущей директории надо сделать

./ct-ng help

Должна вывестись инструкция.

Конфигурируем

./ct-ng menuconfig

Говорят, тем кто собирал линуксовые ядра все должно быть понятно, я просмотрел все опции и потыкал то, что мне надо.

А вообще можно сделать так

./ct-ng list-samples

И выбрать что-то из уже готовых настроек. И затем посмотреть конфигурацию так

./ct-ng show-x86_64-ubuntu16.04-linux-gnu

Выбираем preset

./ct-ng x86_64-ubuntu16.04-linux-gnu

И можно оттюнить с помощью menuconfig

Проблемы

Может случится так, что вы получите такую ошибку

/Volumes/OSXElCapitan/Users/mrdekk/casesafe/.build/src/gdb-7.12.1/gdb/doublest.c:258:19: error: use of undeclared identifier 'min'; did you mean 'fmin'?
[ERROR]    /Volumes/OSXElCapitan/Users/mrdekk/casesafe/.build/src/gdb-7.12.1/gdb/doublest.c:568:19: error: use of undeclared identifier 'min'; did you mean 'fmin'?
[ERROR]    /Volumes/OSXElCapitan/Users/mrdekk/casesafe/.build/src/gdb-7.12.1/gdb/doublest.c:912:25: error: use of undeclared identifier 'min'; did you mean 'fmin'?
[ERROR]    make[3]: *** [doublest.o] Error 1
[ERROR]    make[3]: *** Waiting for unfinished jobs....
[ERROR]    make[2]: *** [all-gdb] Error 2
[ERROR]    make[1]: *** [all] Error 2

Надо попробовать ветку master в crosstool-ng. Однако bash на OSX слишком старый для bootstrap, поэтому придется поставить bash из brew и поправить shell в bootstrap.

После однако начинаются проблемы с sha512sum, такие

/Volumes/OSXElCapitan/Users/mrdekk/Documents/Utils/crosstool-ng/scripts/functions: line 786: sha512sum: command not found

Для этого делаем так

brew install coreutils
ln -s /usr/local/bin/gsha512sum /usr/local/bin/sha512sum

Еще там не собирается glibc с binutils-2.29.1, есть патч, который позволяет так собираться

char *loc1 __attribute__ ((nocommon));
char *loc2 __attribute__ ((nocommon));
compat_symbol (libc, loc1, loc1, GLIBC_2_0);
compat_symbol (libc, loc2, loc2, GLIBC_2_0);

/* Although we do not support the use we define this variable as well.  */
char *locs __attribute__ ((nocommon));
compat_symbol (libc, locs, locs, GLIBC_2_0);

Еще появилась такая проблема

[ERROR]      ../sysdeps/ieee754/dbl-64/e_pow.c:469:13: error: '<<' in boolean context, did you mean '<' ? [-Werror=int-in-bool-context]
[ERROR]      ../sysdeps/ieee754/dbl-64/e_pow.c:471:17: error: '<<' in boolean context, did you mean '<' ? [-Werror=int-in-bool-context]
[ERROR]      ../sysdeps/ieee754/dbl-64/e_pow.c:477:9: error: '<<' in boolean context, did you mean '<' ? [-Werror=int-in-bool-context]
[ERROR]      ../sysdeps/ieee754/dbl-64/e_pow.c:479:13: error: '<<' in boolean context, did you mean '<' ? [-Werror=int-in-bool-context]

Для ее решения есть такой патч

diff --git a/sysdeps/ieee754/dbl-64/e_pow.c b/sysdeps/ieee754/dbl-64/e_pow.c
index 663fa39..bd758b5 100644
--- a/sysdeps/ieee754/dbl-64/e_pow.c
+++ b/sysdeps/ieee754/dbl-64/e_pow.c
@@ -466,15 +466,15 @@  checkint (double x)
     return (n & 1) ? -1 : 1;	/* odd or even */
   if (k > 20)
     {
-      if (n << (k - 20))
+      if (n << (k - 20) != 0)
 	return 0;		/* if not integer */
-      return (n << (k - 21)) ? -1 : 1;
+      return (n << (k - 21) != 0) ? -1 : 1;
     }
   if (n)
     return 0;			/*if  not integer */
   if (k == 20)
     return (m & 1) ? -1 : 1;
-  if (m << (k + 12))
+  if (m << (k + 12) != 0)
     return 0;
-  return (m << (k + 11)) ? -1 : 1;
+  return (m << (k + 11) != 0) ? -1 : 1;
 }

Далее опять проблемы

[ALL  ]      rpc_parse.c: In function 'get_prog_declaration':
[ERROR]      rpc_parse.c:543:23: error: '%d' directive writing between 1 and 10 bytes into a region of size 7 [-Werror=format-overflow=]
[ALL  ]           sprintf (name, "%s%d", ARGNAME, num); /* default name of argument */
[ALL  ]                             ^~
[ALL  ]      rpc_parse.c:543:20: note: directive argument in the range [1, 2147483647]
[ALL  ]           sprintf (name, "%s%d", ARGNAME, num); /* default name of argument */
[ALL  ]                          ^~~~~~
[ALL  ]      rpc_parse.c:543:5: note: 'sprintf' output between 5 and 14 bytes into a destination of size 10
[ALL  ]           sprintf (name, "%s%d", ARGNAME, num); /* default name of argument */
[ALL  ]           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[ALL  ]      cc1: all warnings being treated as errors
[ERROR]      make[3]: *** [/Volumes/OSXElCapitan/Users/mrdekk/casesafe/.build/x86_64-ubuntu16.04-linux-gnu/build/build-libc-final/multilib/sunrpc/rpc_parse.o] Error 1
[ERROR]      make[3]: *** Waiting for unfinished jobs....
[ERROR]      make[2]: *** [sunrpc/others] Error 2
[ERROR]      make[1]: *** [all] Error 2

Решение этой проблемы найти было сложнее, но кажется есть вот

+--- a/sunrpc/rpc_parse.c
++++ b/sunrpc/rpc_parse.c
+@@ -521,7 +521,7 @@ static void
+ get_prog_declaration (declaration * dec, defkind dkind, int num /* arg number */ )
+ {
+   token tok;
+-  char name[10];		/* argument name */
++  char name[MAXLINESIZE];		/* argument name */
+ 
+   if (dkind == DEF_PROGRAM)
+     {

Дальше опять проблемы

nss_nisplus/nisplus-alias.c:300:12: error: argument 1 null where non-null expected [-Werror=nonnull]
[ERROR]      nss_nisplus/nisplus-alias.c:303:39: error: '%s' directive argument is null [-Werror=format-truncation=]
[ERROR]      make[3]: *** [/Volumes/OSXElCapitan/Users/mrdekk/casesafe/.build/x86_64-ubuntu16.04-linux-gnu/build/build-libc-final/multilib/nis/nisplus-alias.os] Error 1
[ERROR]      make[3]: *** Waiting for unfinished jobs....
[ERROR]      make[2]: *** [nis/others] Error 2
[ERROR]      make[1]: *** [all] Error 2

Лечаться так

diff --git a/nis/nss_nisplus/nisplus-alias.c b/nis/nss_nisplus/nisplus-alias.c
index 7f698b4e6d..509ace1f83 100644
--- a/nis/nss_nisplus/nisplus-alias.c
+++ b/nis/nss_nisplus/nisplus-alias.c
@@ -297,10 +297,10 @@  _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias,
       return NSS_STATUS_UNAVAIL;
     }
 
-  char buf[strlen (name) + 9 + tablename_len];
+  char buf[tablename_len + 9];
   int olderr = errno;
 
-  snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
+  snprintf (buf, sizeof (buf), "[name=],%s", tablename_val);
 
   nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);

После этого toolchain собрался. После этого я попробовал собрать простой Hello, World с ним и запустить. На macOS не запустилось (zsh: exec format error: ./CrossWorld) - это хорошо. Собираем простейший контейнер на ubuntu 16.04 и запускаем - работает. Отлично!

Об Actor Model от автора

   

Хорошее видео про Actor Model от автора концепции. Правда, на английском, но если владеете и вам интересна модель акторов, то очень рекомендую посмотреть.

MySQL в Docker через supervisord

     

Крутится тут у меня небольшой контейнер с LAMP стэком (Apache, PHP, MySQL внутри одного контейнера вместе с supervisor). И в последнее время периодически стал вылетать MySQL (стал наедаться памяти). Помогала только ручная перезагрузка контейнера. Добавить памяти был не вариант (сама машинка ограниченная по ресурсам). Пробовал зашедулить в крон перезагрузку контейнера, но работало это плохо. Поэтому решил сделать что-нибудь чтоб жило само и без перезагрузок. Получилось так:

Проблема, как я уже сказал, ввиду ограниченных ресурсов виртуальной машинки - mysql хочет выделить блок памяти, но не может и поэтому падает совсем. Так как на диске место есть поколдуем так. Создадим специальный swap файлик:

dd if=/dev/zero of=/opt/swap.dat bs=1024 count=512k
mkswap /opt/swap.dat
swapon /opt/swap.dat
vim /etc/fstab

Файлик /etc/fstab отредактируем так, надо добавить в него такую строчку

/opt/swap.dat      none    swap    sw      0       0

Далее подредактируем конфиг mysql

vim /etc/mysql/my.cnf

Уменьшим размер буфера

innodb_buffer_pool_size=64M 

И далее пересоберем контейнер и перезапустим. 2 недели - полет нормальный. И да - эта инструкция как заставить работать на слабых конфигурациях. Может работать неоптимально с точки зрения производительности.