Podklady z mého Nix & NixOS workshopu na InstallFestu 2024.
Základy práce s Nixem
Instalace
- Oficiální instalátor: https://nixos.org/download/#download-nix
- Determinate Nix installer:
https://zero-to-nix.com/start/install
- Robustnější
- Nastaví rozumně
nix.conf
(flakes, trusted user) - Telemetrie :-(
Základní příkazy
- Starý nix:
nix-build
,nix-shell
,nix-env
- (-) částečně nekonzistentní přepínače u různých příkazů
- (+) stabilní, dostupná široká funkcionalita
- Experimentální příkaz:
nix
nix build
,nix develop
,nix profile
- (-) je potřeba explicitně povolit:
nix --experimental-features 'nix-command flake'
- konfigurační soubor:
~/.config/nix/nix.conf
- (-) nestabilní, na stabilizaci se pracuje
- (+) konzistentnější přepínače
- (+) TAB-doplňování názvů attributů
Nixpkgs
- Největší repozitář open-source software
- 90 tisíc balíků
- https://github.com/NixOS/nixpkgs/
- https://search.nixos.org/packages
Použití balíku z nixpkgs:
which htop nix-shell -p htop nix shell nixpkgs#htop which htop
Jak použít libovolnou verzi SW?
Použít starší větev nixpkgs:
nix shell nixpkgs/nixos-23.05#htop htop --version exit
- Použít libovolný commit z nixpkgs:
https://lazamar.co.uk/nix-versions/ – zkusíme verzi 3.0.5:
nix-shell -p htop -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/f8f124009497b3f9908f395d2533a990feee1de8.tar.gz nix shell nixpkgs/f8f124009497b3f9908f395d2533a990feee1de8#htop htop --version exit
- Použít aktuální nixpkgs, ale zkompilovat proti tomu starší verzi htopu
- Musí se upravit atribut
src
v “definici” balíku
- Musí se upravit atribut
”Override” atributů v definici balíku
Je lepší si na to vytvořit soubor
shell.nix
:with import <nixpkgs> {}; mkShell { packages = [ bashInteractive (htop.overrideAttrs (old: { src = fetchFromGitHub { owner = "htop-dev"; repo = old.pname; rev = "3.1.0"; hash = ""; # smazat hash!!! }; })) ]; }
- Spustit
nix-shell
a doplnit hash podle chybové hlášky Otestujeme:
nix-shell htop --version which htop
- Aby i název cesty v
/nix/store
obsahoval správnou verzi, je potřeba změnit i atributversion
Změna více atributů
Přidání
version
(nezapomenout narec
)with import <nixpkgs> {}; mkShell { packages = [ bashInteractive (htop.overrideAttrs (old: rec { version = "3.1.0"; src = fetchFromGitHub { owner = "htop-dev"; repo = old.pname; rev = version; hash = "sha256-/48Ca7JPzhPS4eYsPbwbSVcx9aS1f0LHcqsbNVWL+9k="; }; })) ]; }
- Občas je potřeba změnit i jiné atributy (závislosti, configure flags, …)
Jak vytvořit balíček?
- Použít nástroj
nix-init
pro vytvoření kostry balíku.- Výstup předpokládá, že tvoříme balík pro nixpkgs, což je funkce,
která bude zavolána v rámci
callPackage
z nixpkgs. - Pokud chceme balík mimo nixpkgs, můžeme nahradit parametr funkce
(
{...}:
) zawith import <nixpkgs> {};
- Výstup předpokládá, že tvoříme balík pro nixpkgs, což je funkce,
která bude zavolána v rámci
Zkusíme balík přeložit (pravděpodobně to nepůjde bez úprav):
nix-build
Výsledek uvidíme za symlinkem
result
:ls -l ./result/
- Typické úpravy
default.nix
:- Přidání závislostí (
buildInputs
,nativeBuildInputs
,propagatedBuildInputs
, …) - Nastavení parametrů pro
./configure
,make
,cmake
,meson
apod. - Instalace do
$out
- Patchování nekompatibilit s Nixem
- Přidání závislostí (
- Neocenitelný pomocník:
nix-shell
(bez -p) nebonix develop
:
Ladění pomocí nix-shell/nix develop
nix-shell # Všechny atributy derivation dostupné jako proměnné prostředí echo $version echo $src # Vlastní sestavení balíku je (v nixpkgs) realizováno funkcí genericBuild type genericBuild type buildPhase genericBuild # interaktivní řešení problémů
Příklad
Vygenerujeme kostru pomocí
nix-init
$ nix-init --url https://pypi.org/project/pynostr/ Enter tag or revision (defaults to 0.6.2) ❯ 0.6.2 Enter version ❯ 0.6.2 Enter pname ❯ pynostr How should this package be built? ❯ 1 - buildPythonPackage Enter output path (leave as empty for the current directory) ❯ .
Vytvoříme
shell.nix
, kam balík natáhneme volánímcallPackage
:with import <nixpkgs> {}; mkShell { packages = [ bashInteractive (python3Packages.callPackage ./default.nix {}) ]; }
Otestujeme (a zjistíme, že kostru v
default.nix
už není potřeba upravovat):$ nix-shell $ python from pynostr.key import PrivateKey private_key = PrivateKey() public_key = private_key.public_key print(f"Private key: {private_key.bech32()}") print(f"Public key: {public_key.bech32()}")
Vlastní distribuce založená na NixOS
- Myšlenka NixOSu
- Linuxová distribuce = balík, který závisí na jiných balících + konfigurační soubory, aby spolu balíky dobře fungovaly
- Nix je dobrý v kompilaci balíků a řešení závislostí, abychom měli Linuxovou distribuci, potřebujeme vyřešit konfiguraci
- NixOS = Nix kód pro automatické generování konfiguračních souborů
Vlastní distribuce
Vytvoříme soubor
configuration.nix
{ config, pkgs, ... }: { boot.loader.systemd-boot.enable = true; networking.hostName = "InstallFest"; time.timeZone = "Europe/Prague"; services.openssh.enable = true; services.xserver.enable = true; services.xserver.displayManager.lightdm.enable = true; services.xserver.desktopManager.xfce.enable = true; environment.systemPackages = with pkgs; [ emacs wget ]; users.users.alice = { isNormalUser = true; extraGroups = [ "wheel" ]; # secret hashedPassword = "$6$UeUi3mis.Na253Zz$l3RlyTEn8ZI0eFUgyJAwjvxr.TMx8rZc1sP/2qbKke1p4fxbSLx2iQ1mV5Qot3p9mofxWcPLxSnH/ciOYo3Pu0"; packages = with pkgs; [ firefox thunderbird ]; }; documentation.nixos.enable = false; system.stateVersion = "23.11"; }
nix-shell -p nixos-rebuild # Test the system in a VM nixos-rebuild build-vm --no-flake -I nixos-config=$PWD/configuration.nix ./result/bin/run-InstallFest-vm # Deploy to a remote NixOS computer nixos-rebuild switch --no-flake -I nixos-config=$PWD/configuration.nix --target-host example.com
Testování s nixos-shell
- Nástroj
nixos-shell
(neplést snix-shell
) vytvoří VM dle NixOS konfigurace v souboru./vm.nix
(default), nabootuje jí v qmeu vm.nix
{ config, pkgs, ... }: { networking.hostName = "InstallFest"; environment.systemPackages = with pkgs; [ htop ]; documentation.nixos.enable = false; system.stateVersion = "23.11"; }
nix-shell -p nixos-shell nixos-shell
Kontejnery bez zbytečného balastu
- Kontejnery se často generují z Alpine Linuxu – používá malou musl libc
S Nixem můžete snadno docílit toho samého:
nix-build --expr 'with (import <nixpkgs> {}); ministat' nix-tree ./result/ # 30 MB nix-build --expr 'with (import <nixpkgs> {}).pkgsMusl; ministat' nix-tree ./result/ # 3 MB nix-build --expr 'with (import <nixpkgs> {}).pkgsStatic; ministat' nix-tree ./result/ # 80 kB
Tvorba Docker kontejneru z libovolných Nix balíků
Vytvoříme soubor
default.nix
s následujícím obsahem:{ pkgs ? import <nixpkgs> {} }: pkgs.dockerTools.buildImage { name = "ministat"; tag = "latest"; config = { Cmd = [ "${pkgs.ministat}/bin/ministat" ]; }; }
${pkgs.ministat}
můžeme nahradit${pkgs.pkgsStatic.ministat}
Spuštění v kontejneru
nix-build docker load < result docker run -it ministat
Layered image
- Místo
dockerTools.buildImage
lze použítdockerTools.buildLayeredImage
, který dá každý Nix balík do samostatné vrstvy (pokud jich není víc než 256). - Zlepší upload časy změněného obrazu
Binární kompatibilita s FHS distribucemi
- buildFHSEnv
- nix-ld
- envfs
- buildFHSEnv – binárky použitelné jinde
patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 a.out
- build proti staré glibc
- Použít starší nixpkgs
- Zkusit https://github.com/wheybags/glibc_version_header
Table of Contents
Below are notes for my Nix workshop at Installfest. https://pretalx.installfest.cz/installfest-2022/talk/QDTPQL/
1. Why Nix?
- Reproducible
- Build exactly the same software on different systems.
- Declarative
- Store your development environment in a simple file/git.
- “Reliable”
- Nix ensures that installing or upgrading one package cannot break other packages.
2. Basics
2.1. Commands
- Classic:
nix-build
,nix-shell
,nix-env
- older, incoherent, …
- Experimental:
nix
nix build
,nix develop
,nix profile
- needs to be explicitly enabled:
nix --experimental-features nix-command flake
- config file:
~/.config/nix/nix.conf
2.1.1. Package management
apt | Nix classic | Nix (flakes see later) |
---|---|---|
apt install mc | nix-env -iA nixpkgs.mc | nix profile install nixpkgs#mc |
dpkg -l | nix-env -q | nix profile list |
apt remove mc | nix-env -e mc | nix profile remove … |
apt upgrade mc | nix-env -uA nixpkgs.mc | nix profile upgrade .. |
- Features:
- No root required
- Installed into
~./nix-profile/bin
ls -l ~/.nix-profile ls -lH ~/.nix-profile
Updating
nix-channel --list # channel = package repository nix-channel --update # similar to apt update nix-env --upgrade # upgrade installed packages to channel version
2.1.2. Searching
apt | Nix classic | Nix (flakes see later) |
---|---|---|
apt-cache search … | nix-index + nix-locate | nix search nixpkgs … |
(3rd party tool) |
3. Under the hood
3.1. Nix store
ls -l /nix/store | head ls -lh $(which bash) tree $(dirname $(readlink $(which bash)))/.. | head
3.2. Profiles
https://nixos.org/manual/nix/stable/package-management/profiles.html
ls -l /nix/var/nix/profiles/per-user/$USER
- Easy to switch to older versions
nix-env --rollback nix-env --list-generations nix-env --switch-generation 43
Comparing generations (experimental nix)
nix profile diff-closures
4. Nixpkgs
- Collection of Nix expressions for building software
- Whole Linux distribution in one repository
- Ranks well in https://repology.org/ top repositories
- https://github.com/NixOS/nixpkgs/
- https://nixos.org/manual/nixpkgs/unstable/
4.1. Structure
pkgs
– packages (programs/libraries/…)nixos
– Linux distribution based on nixpkgslib
– helper functionspkgs/top-level/all-packages.nix
– list of top-level “attributes”Searching: search for “attrname<space>=”
cd nixpkgs grep -r 'gnuplot =' .
4.2. Building/Modifying packages
nix-build '<nixpkgs>' -A gnuplot git clone https://github.com/NixOS/nixpkgs/ nix-build ./nixpkgs -A gnuplot edit ./nixpkgs/pkgs/tools/graphics/gnuplot/default.nix nix-build ./nixpkgs -A gnuplot ls -l result nix log result/ # show build log nix log /nix/store/mr9l6qjimaarcak7s5rk6j1h4b16rpw9-gnuplot-5.4.3 # See the log from “distro” build nix log $(dirname $(readlink $(which bash)))/.. cd nixpkgs # Rebuild all packages depending on nixpkgs-review wip
4.2.1. Nix output monitor
Let’s have better understanding what happens during building:
NIXPKGS_ALLOW_UNFREE=1 \ nix-build $HOME/.cache/nixpkgs-review/rev-877f0e97eb2eff62e675b75dfe19940400b2ed09-dirty/build.nix \ --arg pkgs 'import <nixpkgs> {}' |& nom
Unfortunately does not work with experimental nix
command, but will
probably implement this in the future.
4.2.2. Examining dependencies
nix-tree ./result/
5. Development environments
Task | Nix classic | Nix |
---|---|---|
Temporary package installation | nix-shell -p | nix shell |
Enter build environment of a package | nix-shell | nix develop |
5.1. Install packages temporarily
mc --version echo $PATH echo $PATH | tr : \\n nix-shell -p mc mc --version echo $PATH | tr : \\n exit nix-shell --pure -p mc # only explicitly mentioned dependencies are available echo $PATH | tr : \\n exit
nix-shell -p mc -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/d1c3fea7ecbed758168787fe4e4a3157e52bc808.tar.gz
5.1.1. Experimental nix, flakes
- Discoverability, CLI completion
nix shell nixpkgs#gnuplot nix run nixpkgs#gnuplot
5.2. Existing package development/hacking
Traditionally:
./configure sudo apt install ... ./configure sudo apt install ... ./configure sudo apt install ...
With nix:
git clone https://github.com/MidnightCommander/mc.git cd mc ./autogen.sh nix-shell '<nixpkgs>' -A mc ./autogen.sh ./configure make -j$(nproc)
5.3. Per-project development environments
- One does not need to relay only on packages in nixpkgs
- Source can contain Nix files (e.g.
default.nix
,shell.nix
,flake.nix
)
git clone https://github.com/wentasah/boardproxy cd boardproxy make # fails due to missing dependencies nix-shell # make deps from shell.nix or default.nix available make # success
Just building the package:
nix-build
- Drawback: every single change in the source code rebuilds everything
5.3.1. Entering the environment automatically
- direnv, lorri, nix-direnv
Needs to be installed and configured (simpler on NixOS)
nix-env -i -A direnv -A lorri cd my-project lorri init # creates shell.nix template unless it exists direnv allow cd .. cd - edit shell.nix
6. How are Nix derivations built?
Nix expression is evaluated → low-level derivation
nix-build '<nixpkgs>' -A gnuplot ls -l result nix-store --query --deriver result/ nix show-derivation result/ # pretty format cat "/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"
- Important attributes:
builder
,args
- Most attributes (and their values) are propagated to environment variables
nix-shell '<nixpkgs>' -A gnuplot printenv type genericBuild type buildPhase type configurePhase unpackPhase cd gnuplot-5.4.3 configurePhase buildPhase
- invalidace hash (aby se projevil update)
7. Generating Docker images from Nix packages
- https://nix.dev/tutorials/building-and-running-docker-images
https://nixos.org/manual/nixpkgs/unstable/#sec-pkgs-dockerTools
{ pkgs ? import <nixpkgs> {} }: pkgs.dockerTools.buildImage { name = "gnuplot"; config = { Cmd = [ "${pkgs.gnuplot}/bin/gnuplot" ]; }; }
7.1. Running
nix-build docker-image.nix docker load < result docker run -it gnuplot:nmg0lnkf1dl7a0bsv152a6xphkxm9sq9
7.2. What’s inside?
mkdir tmp && cd tmp
tar xf ../result
ls -lR
tar tf */layer.tar
7.3. Image from custom package
{ pkgs ? import <nixpkgs> {} , boardproxy ? import ./boardproxy/default.nix { inherit pkgs; } }: pkgs.dockerTools.buildImage { name = "boardproxy"; config = { Entrypoint = "${boardproxy}/bin/boardproxy"; }; }
nix-build docker-boardproxy.nix docker load < result docker run -it boardproxy:60j25jpwggspx1mg694143ddchsynq1q --help
7.4. Smaller image needed?
https://nixos.org/#asciinema-demo-cover
{ pkgs ? import <nixpkgs> {} }: pkgs.redis.overrideAttrs (old: { # no need for systemd support in our docker image makeFlags = old.makeFlags ++ ["USE_SYSTEMD=no"]; # build static binary with musl preBuild = '' makeFlagsArray=(PREFIX="$out" CC="${pkgs.musl.dev}/bin/musl-gcc -static" CFLAGS="-I${pkgs.musl.dev}/include" LDFLAGS="-L${pkgs.musl.dev}/lib") ''; # Let's remove some binaries which we don't need postInstall = "rm -f $out/bin/redis-{benchmark,check-*,cli}"; })
8. Flakes intro
8.1. Problems of clasic Nix
- What is inside a repo? Difficult to figure out without reading all *.nix files.
- No enforcment of naming .nix files (default.nix, shell.nix, …)
- What does
<nixpkgs>
mean? Depends on the value of $NIXPATH env. var. nix-env
operation depends on the content of~/.nix-defexpr/
.- Evaluation of Nix expressions can read arbitrary files on your disk. Harms reproducibility.
8.2. How do flakes solve it?
- Hermetic isolation of Nix evaluation (no NIXPATH, no arbitrary files).
- Only files from the same git repo can be read.
- => Makes it possible to cache results of evaluation.
- Defines a structure of repository “entry point” (flake.nix).
- Predefined attribute names for packages, overlays, tests, …
- Explicit references with versions to other sources, e.g. nixpkgs.
- lock files
8.3. Drawbacks of flakes
- One more thing to learn.
- Lower motivation to include software into nixpkgs (can be separate flake)
9. Other notes
- nixGL – running OpenGL apps from nixpkgs on other distros
- Remote builds
- slow laptop?
nix --builders ssh://server --max-jobs 0
- build on
server
, no local builds (except simple ones, i.e. runCommdnLocal)
- build on
10. Pros and cons
- Nix vs. Docker
- Docker solves problems of traditional package managers by building on top of them
- Nix changes (fixes) the core of package management
- Nix is (largely) reproducible
- Declarative specifications of build/development/production environments
- Nix is difficult to learn
- Using unpackaged applications (especially proprietary) is more difficult
- buildFHSUserEnv
- nix-ld
- autopatchelf-hook
Table of Contents
Below are the materials from my today’s Installfest talk. https://pretalx.installfest.cz/installfest-2022/talk/Z8TP3D/
1. Characteristics
- New language – announced 2012
- Goal: Solve the “two language” problem
- Prototype in Python, rewrite in C++ for speed
- Compiled language (LLVM)
- Good for interactive work (JIT)
- Dynamic types + type inference
- Garbage collected
- Multiple dispatch paradigm
- one function can have different implementations based on type of all arguments
- Lisp-like macros
- Target domain:
- Originally: Scientific computations
- Nowadays: General purpose, Data Science, Visualisation, …
1.1. Speed
Source: https://youtu.be/LT4AP7CUMAw
1.2. My success story
- Load & process 2GB CSV file
- Julia: 40s, 5 GB of memory
- Python Pandas: 5 min, OUT OF MEMORY
- Python Pandas + big machine: 15 min, 36 GB of memory
2. Installation
- distribution package managers
- download archive, unzip/untar, run
- console application
2.1. IDE: Julia plugin for VS Code
3. Calculator
1 + 1 3 * 5
4. REPL modes
Special characters at the start of the line switch modes:
Help
?atan
Shell
;ls
Package manager
]add IJulia
Return with backspace
5. Variables
x = 1 x # Julia likes Unicode :-) π # Enter as \pi<TAB> α = atan(1/2) 3α + 100 # You can skip multiply operator
6. Vectors, Arrays
a=[10,20,30] a[1] # one-based indexing a[2:3] a[2:end] b=[1 2; 3 4] c=[5 6 7 8]
6.1. Element-wise operations – broadcasting
a=rand(10_000_000) b=rand(10_000_000) a*b # ❌ a.*b sin(a) # ❌ sin.(a) # Broadcasting [sin(i) for i in a] # Comprehension # Broadcasting is faster – no need to # allocate intermediate memory @time sin.(a) .+ cos.(b); @time [sin(i) for i in a] .+ [cos(i) for i in b]; # In-place assignment (no memory allocation) c = zeros(size(a)) @time c .= sin.(a).^2 .+ cos.(b).^2; # Tired of writing dots? @. c = sin(a)^2 + cos(b)^2
6.2. GPU arrays
- Available APIs
- CUDA.jl
- AMDGPU.jl
- oneAPI.jl (Intel)
High-level (array) API:
using oneAPI oneAPI.versioninfo() a=rand(100_000_000) b=rand(100_000_000) c=zeros(size(a)) @time c .= a .* b; ga = oneArray(a) gb = oneArray(b) gc = oneArray(c) @time gc .= ga .* gb;
- Possibility to write GPU kernels in Julia
7. Types
Julia uses dynamic types + type inference.
typeof(1) typeof(1.0) typeof(Int8(1)) typeof("Hello world")
7.1. Parametric types
1//3 typeof(ans) # ans = result of previous line typeof(Int8(1)//Int8(3)) typeof([1,2,3]) typeof([1 2 3]) typeof(Int8[1,2,3]) typeof([1 2;3 4.1])
7.2. Abstract types and type hierarchy
“is subtype” operator: <:
Integer <: Number Int8 <: Integer Int8 <: Number Float32 <: Number Float32 <: Integer
7.3. User-defined types
mutable struct MyType id::Int64 text::String end x = MyType(10, "Hello") # Define addition of our type Base.:+(a::MyType, b::MyType) = MyType(a.id + b.id, "Sum") x + MyType(1, "xxx")
8. Functions
# Mathematics-like definition square(x) = x*x square(4) # Programming-like definition function hello(name) return "Hello " * name end hello("Michal") square("Hello") # Operators are functions too +(1,2) →(a,b) = (a+b)/(a-b) 3→1
8.1. Anonymous functions
Functional programming features.
x->x^2 ans(5) # call a=rand(10) # Return elements > 0.5 filter(x->x>0.5, a) [x for x in a if x > 0.5] a[a .> 0.5]
8.2. Methods and multiple dispatch
Functions can have multiple methods (implementations). The method to call is selected based on types of all arguments.
fun(x::Number) = "Number "*string(x) methods(fun) fun(1) fun(1.1) fun("1.1") fun(x::String) = "String "*x methods(fun) fun("1.1") # Functions can have many methods methods(+) methods(show)
8.3. Multimedia I/O (show examples)
Values can be presented in different formats:
@doc atan typeof(@doc atan) show(stdout, MIME("text/plain"), @doc atan) show(stdout, MIME("text/html"), @doc atan)
9. Macros
- Inspired by Lisp
- Work at abstract syntax tree level.
- Can rewrite/generate programs.
- Often used for domain specific languages
- No separate macro language, macros are written in Julia itself.
9.1. Examples
9.1.1. Unit testing
using Test @test 1 + 1 == 2
9.1.2. Code simplification
sqrt(abs(sin(1))) # Pipe syntax (for unary functions only) 1 |> sin |> abs |> sqrt rnd = rand(10) sort(rnd, rev=true) .+ 1 # Pipes with higher-arity functions ⇒ lambdas rnd |> x -> sort(x, rev=true) |> x -> x .+ 1 using Pipe # Piped value represented by underscore @pipe rnd |> sort(_, rev=true) |> _ .+ 1
- Similar: Chains.jl, DataFramesMeta.jl, …
@chain df begin dropmissing filter(:id => >(6), _) groupby(:group) combine(:age => sum) end
9.2. Benchmarking, code inspection, optimization
@time rand(Int(1e6)); using BenchmarkTools @benchmark rand(Int(1e6)) @code_native sum(1:5) a = [1, 2, 3] # Don’t perform bounds checking @inbounds a[2]
10. Showcase
Example of what is possible with the language. This is not builtin functionality. Everything is programmed in Julia.
10.1. Measurements
Computation with confidence intervals
using Measurements
a = 5.2 ± 1.0
typeof(a)
b = 3.7 ± 1.0
a + b
a * b
a / b
10.2. Unitful
using Unitful using Unitful.DefaultSymbols using Unitful: hr 1m + 3cm |> cm |> float sin(90) sin(90°) sin(π/2) 15m/3s 10km/hr |> m/s 10km/hr |> m/s |> float 0°C |> K |> float
11. Plotting
- Plots supports multiple plotting backends (e.g. Python matplotlib).
- Infamous “Time to first plot” – much better today
using Plots
plot(sin.(0:0.1:2π))
- One of several available interfaces to Gnuplot.
- Faster than Plots
using Gnuplot @gp sin.(0:0.1:2π) "with lines lw 5" "set grid"
12. Package management
- Fast development, breaking changes (packages with version < 1.0)
- Reproducible environments (projects)
- Which packages and versions
- Project.toml, Manifest.toml
- Needs manual setup
12.1. Package manager
pwd() # Switch to package manager ] ? # create a new project or activate existing activate . add Pipe ;cat Project.toml cat Manifest.toml
12.2. Using packages, modules
Module = namespace
module MyMod export x x=1 y=2 end x MyMod.x
- Package is a git repo with certain structure
# introduce exported symbols to current namespace using Package # introduce just the symbol Package to current namespace import Package
13. Tasks & Channels
- Easy to use parallelism
- Similar to goroutines in Go
14. Interfacing other languages
Direct call to a function from shared library:
# libc call ccall(:clock, Int32, ()) # using other libraries ccall((:zlibVersion, "libz"), Cstring, ()) |> unsafe_string
Python code can be called transparently from Julia:
using PyCall math = pyimport("math") math.sin(math.pi / 4) # returns ≈ 1/√2 = 0.70710678...
15. Interactive notebooks
- Jupyter vs. Pluto.jl
- Pluto is something between Jupyter and Excel
15.1. Jupyter
using IJulia
notebook()
15.2. Pluto.jl
import Pluto
Pluto.run()
15.3. Feature comparison
Feature | Jupyter | Pluto.jl |
---|---|---|
Languages | many | Julia |
File format | JSON | Julia script with comments |
Results | Stored in JSON | Available only at runtime |
Execution order | Top-down/manual | Dependency-based |
Cell updates | Manual | Automatic |
Package management | No | Yes, reproducible |
16. Dataframes.jl
- Work with tabular data, named columns
- Easy import from CSV (CSV.jl)
17. Conclusion
- ➕ “Simple”, fast, versatile language
- ➕ A lot of packages available
- ➕ Active community
- ➖ Some packages are not mature, breaking changes
- ➖ Compilation can be slow (new session)
Recently, I worked on a visual object tracker implemented in C++. The project has several compile configurations and a time-consuming test suite, some parts of which need a GPU not present in my laptop. Because many parts of the code depend heavily on compile configuration, changing them requires recompilation and ideally also retesting of all configurations to make sure that everything works correctly. Since my development laptop not only lacks the GPU needed for testing but also has only four cores, which makes the compilation unnecessarily slow, I looked for an easy way to compile and test the code being edited on a powerful remote server.
Initially, I tried to use git commit
and git push
to capture the
state of the working directory and transfer it to the remote server,
but this was not ideal for many reasons. Then I discovered git stash
create
, which captures the state of the working directory and creates
a “volatile” commit object not attached to any branch. This command
became the basis of my git-sarah
script, which is an acronym
standing for git stash and run at host, and you can see find its
code below.
With git-sarah
script, instead of instructing my editor or IDE to
run:
make
I instruct it to run the following:
git sarah example.org dir -- make
This command copies the current state of the work tree to $HOME/dir
on the example.org server and runs make
in the directory
corresponding to the current directory on the local host. For example,
if the current local directory is ~/projects/kcf/src
, with kcf
being the root directory of the git repository, the make
command
will be run in $HOME/dir/src
on the server. In the output (both
stdout and stderr) of the command, the path of the server directory,
e.g., /home/mylogin/dir
is replaced with its local counterpart:
/home/me/projects/kcf
.
If a single command (make
) is not enough, you can instruct
git-sarah
to run commands from a script (e.g., commands.sh
), which
need not to be stored in your git repository. For that, run:
git sarah example.org dir -- sh < ./commands.sh
The code of git-sarah
(further development happens on GitHub) is quite simple:
#!/bin/bash set -e -o pipefail OPTS_SPEC="\ git sarah <host> <remote_dir> [ -- ] [ command ... ] git stash and run at host -- h,help show the help " eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)" echo "$*" while \[[ $# -gt 0 ]]; do case "$1" in -h) exit 0;; --) shift; break;; esac shift done HOST=${1:?Host not specified}; shift DIR=${1:?Remote directory not specified}; shift PREFIX=$(git rev-parse --show-prefix) worktree=$(git stash create) worktree=${worktree:-HEAD} git push -f $HOST:$DIR $worktree:refs/heads/git-sarah # Use ssh to translate possibly relative $DIR to the absolute one. ABS_DIR=$(ssh "$HOST" "cd '$DIR' && pwd") # Run the command at $HOST and translate its output so that # file/directory names appear as on localhost. Use perl's \Q to limit # the possibility of interpretating ABS_DIR as a search pattern. ssh "$HOST" "cd '$DIR/$PREFIX' && git -c advice.detachedHead='' checkout --detach git-sarah && ${*:?Command not specified}" \ |& perl -pe "s|\Q${ABS_DIR}\E|$(git rev-parse --show-toplevel)|g"
Table of Contents
Transcript of my seminar about Julia language.
Calculator
1 + 1 3 * 5
Variables
x = 1 x π # Enter as \pi<TAB> α = atan(1/2) 3α + 100
Vectors, Arrays
a=[10,20,30]
a[1]
a[2:3]
a[2:end]
b=[1 2; 3 4]
Element-wise operations – broadcasting
a=rand(100_000_000) b=rand(100_000_000) a*b a.*b sin(a) sin.(a) [sin(i) for i in a] @time sin.(a) .+ cos.(b); @time [sin(i) for i in a] .+ [cos(i) for i in b]; c = zeros(size(a)) @time c .= sin.(a).^2 .+ cos.(b).^2; @. c = sin(a)^2 + cos(b)^2
REPL modes
Help
?atan @doc atan
Shell
;ls
Package manager
]add IJulia
Return with backspace
Types
Julia uses dynamic types + type inference.
typeof(1) typeof(1.0) typeof(Int8(1)) typeof("Hello world")
Parametric types
1//3 typeof(ans) typeof(Int8(1)//Int8(3)) [1,2,3] [1 2 3] Int8[1,2,3] [1 2;3 4.1]
Abstract types and type hierarchy
Integer <: Number Int8 <: Integer Int8 <: Number Float32 <: Number Float32 <: Integer
Functions
f(x) = x*x f(4) function hello(name) return "Hello " * name end hello("Michal") f("Hello") +(1,2) →(a,b) = (a+b)/(a-b) 3→1
Anonymous functions
x->x^2 ans(5) a=rand(10) filter(x->x>0.5, a) [x for x in a if x > 0.5] a[a .> 0.5]
Methods and multiple dispatch
Function can have multiple implementations. The implementation to call is selected based on argument types
f(x::Number) = "Number "*string(x) methods(f) f(1) f(1.1) f("1.1") f(x::String) = "String "*x f("1.1") methods(+) methods(show)
Show examples
@doc atan typeof(@doc atan) show(stdout, MIME("text/plain"), @doc atan) show(stdout, MIME("text/html"), @doc atan) typeof(`ls`) run(`ls`)
Units
Example of what is possible with the language. This is not a builtin functionality. Everything is programmed in Julia.
using Unitful using Unitful.DefaultSymbols using Unitful: hr 1m + 3cm |> cm |> float float(cm(1m + 3cm)) 1m + 3cm |> cm |> float sin(90) sin(90°) sin(π/2) 15m/3s 10km/hr |> m/s 10km/hr |> m/s |> float 0°C |> K |> float
Plotting
Plots supports multiple plotting backends.
using Plots
pyplot()
plot(sin.(0:0.1:2π)
One of several available interfaces to Gnuplot.
using Gaston
plot(sin.(0:0.1:2π)
Macros
- Inspired by Lisp
- Work at parse tree level.
- Can rewrite/generate programs.
- No separate macro language, macros are written in Julia itself.
Examples (see test suites of many Julia packages):
@testset @test
Tasks & Channels
- Easy to use parallelism
Jupyter notebooks
using IJulia
notebook()
Integration with C/C++
Direct call to a function from shared library:
ccall(:clock, Int32, ()) ccall((:clock, "libc"), Int32, ())
Interactive C++
using Cxx cxx"#include <stdio.h>" icxx"""printf("Hello world\n");"""
# Passing Julia values to C/C++ functions x = 42 @cxx printf(pointer("X is %d\n"), x)
Complex example
Testing a C++ class and plotting results of its work.
using Cxx import Cxx.CxxCore using Gaston cxx""" #include "stepper.cpp" """ # Create C++ object and store it in Julia variable s = icxx"Stepper(nullptr, 2020, 100, 20);" # Call a method of C++ object @cxx s->moveTo(2000) pos = Int32[0] freq = Int32[0] while @cxx s->isMoving() @cxx s->periodic() # Store values from the C++ object in Julia array for later # plotting push!(freq, @cxx s->freq) push!(pos, @cxx s->getPosition()) end # Plot gathered data set(grid="on") x=0:length(freq)-1 plot(x, freq, xlabel="iteration", legend="freq") plot!(x, [0; pos[2:end] .- pos[1:end-1]]./20e-3, plotstyle="points", color="red", legend="Δpos/T_s") plot!(x, pos, plotstyle="linespoints", color="green", legend="pos") # Cxx cannot (yet) change functions once that are defined. Use these # to commands to “replace” the compiler object, which allows # redefining the functions. Cxx.CxxCore.reset_init!() Cxx.new_clang_instance()
When studying Linux kernel sources, it’s often helpful to use ftrace’s
function_graph
tracer, which traces function entry and exit points
and clearly shows how functions call each other.
Sometimes, it is useful to get such a trace from other code than the
Linux kernel. In case of C++ this is pretty easy, but for plain C, it
is trickier. I came up with the following to print nice traces. It
uses GCC cleanup
variable attribute to register a function exit
callback.
#include <stdio.h> int trace_indent = 2; char trace_filler[] = {[0 ... 99] = ' '}; static void trace_end(const char **func) { trace_indent--; fprintf(stderr, "%.*s}\n", 4*trace_indent, trace_filler); } #define TRACE(format, ...) \ const char *__tracer __attribute__ ((__cleanup__(trace_end))) = __func__; \ fprintf(stderr, "%.*s%s(" format ") {\n", 4*trace_indent, trace_filler, __func__, ##__VA_ARGS__); \ trace_indent++;
It can be used this way:
void bar() { TRACE(); } void foo(char *str) { TRACE("str=%s", str); bar(); } int main(int argc, char *argv[]) { TRACE("argc=%d", argc); foo("xxx"); return 0; }
When this program is run, it prints:
main(argc=1) { foo(str=xxx) { bar() { } } }
„Slidy“ z mého workshopu na Installfestu. K dispozici i ve formě org-mode zdrojáku, jen je potřeba změnit příponu z .txt na .org.
Table of Contents
About
- ASCII by mělo být spíš UTF-8, ale to nezní tak „cool“ :-)
- O mě
- Pracuji na ČVUT, FEL
- Embedded systémy (≈ low-level stuff)
- Emacs používám od r. 1998
- Patřím k lidem, kteří v Emacsu žijí
- Vim používám také a nic proti němu nemám :-)
Org-mode
- Pokud je Emacs označován jako operační systém, org-mode bychom mohli nazvat kancelářský balík
- Outliner
- Základní funkcionalita; snaha je, aby další funkce nekomplikovaly použití org-mode jako outlineru.
- Značkovací jazyk (markup)
- Prostředí pro přípravu textových dokumentů
- Tabulkový kalkulátor
- Kalendář, plánovač, organizér
- a určitě mnoho dalšího…
- Dokumentace: «C-h i d m org RET»
- Nekonečné možnosti konfigurace
- «M-x customize-group RET org RET»
Outliner
- Nadpisy
^*+
- M-RET – nový nadpis
- M-šipky, M-S-šipky – změny úrovně či pořadí
- C-c C-u – o úroveň výš, C-c C-j – skok, info:org#Motion
- Schovávání: TAB, S-TAB
- Seznamy
- odrážkové, číslované, …
- S-←,→
- Mnohé klávesové zkratky stejné jako u nadpisů
- Konverze «C-c *», «C-c -»
Značkovací jazyk (markup)
- Tučné, kurzíva, podtrženo
verbatim
,přeskrtnuto,kód
α, - Tabulky – nejsnadnější zadávaní jednoduchých tabulek do počítače
| xxx | yyy «TAB»
- Obrázky:
[[./file.jpg]]
- Příklady, zdrojáky se zvýrazňováním syntaxe
- Zkratky:
<e «TAB»
,<s «TAB»
- Zkratky:
Příklad
print("String " + number)
Odkazy
[[cíl][popis]]
nebo[[cíl]]
- Web Installfestu «C-c C-l», «C-c C-o»
- Cíle odkazů
„Rádiové cíle“:
<<<rádio>>>
rádioPříklad: Rádio bylo vynalezeno roku 1893.
Organizace
- Todo – každý nadpis může být položkou „TODO“ «S-←,→»
- Seznam stavů je konfigurovatelný
- «C-c a t» – all TODOs = agenda
- Seznam souborů pro tvorbu agendy (např. jeden .org soubor pro projekt)
- Scheduled/deadline: C-c C-s, C-c C-d
- «.» = dnes, «S-šipky»
- Rozumí i textu: např. „May 1“ nebo „Wed“
- Záznam odpracovaného času na úkolech «C-c C-x C-i», «C-c C-x C-o»
- Souhrn splnění podúkolů
[/]
,[%]
[ ]
Checkboxy «C-c C-c»- Tagy u nadpisů :tag:, «C-c C-c»
- hledání podle tagů: «C-c a m»
Rychlý záznam TODO (capture)
- Vyžaduje konfiguraci
- Globální klávesa «C-c c»
- Šablony - předvyplněný obsah, kam se má „TODO“ uložit
(setq org-capture-templates '(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks") "* TODO %?\n %i\n %a") ("j" "Journal" entry (file+datetree "~/org/journal.org") "* %?\nEntered on %U\n %i\n %a")))
Export
- «C-c C-e»
- Plain text, HTML, OpenDocument, …
- Relativně snadná tvorba vlastních exportů (např. Doxygen)
- Nastavení exportu v hlavičce – «C-c C-e #»
Babel
- Práce se zdrojovými kódy
- Podpora více jazyků v jednom dokumentu a interakce mezi nimi
- „Literate programming“
- „Reproducible research“ (executable documentation)
for i in $(seq 3); do date; sleep 1; done ls -l
Výsledky vidíme níže:
Wed 8 Mar 10:44:56 CET 2017 Wed 8 Mar 10:44:57 CET 2017 Wed 8 Mar 10:44:58 CET 2017 total 24 -rw-r--r-- 1 wsh wsh 6696 Mar 5 21:52 graph.png -rw-r--r-- 1 wsh wsh 6232 Mar 8 10:42 index.org -rw-r--r-- 1 wsh wsh 6232 Mar 8 10:44 org-mode.txt
- Editace: «C-c ’»
- Spuštění: «C-c C-c»
- Argumenty v hlavičce
- :results verbatim drawer
Babel example
Run the benchmark (shell script) on a remote server:
mbw -a -q 10 | awk '{ print $1, $3, $9 }'
0 | MEMCPY | 2193.945 |
1 | MEMCPY | 2334.267 |
2 | MEMCPY | 2368.546 |
3 | MEMCPY | 2396.358 |
4 | MEMCPY | 2411.382 |
5 | MEMCPY | 2417.211 |
6 | MEMCPY | 2434.867 |
7 | MEMCPY | 2436.054 |
8 | MEMCPY | 2433.682 |
9 | MEMCPY | 2460.025 |
0 | DUMB | 2494.388 |
1 | DUMB | 2513.826 |
2 | DUMB | 2511.301 |
3 | DUMB | 2508.781 |
4 | DUMB | 2506.894 |
5 | DUMB | 2510.67 |
6 | DUMB | 2508.151 |
7 | DUMB | 2518.892 |
8 | DUMB | 2475.86 |
9 | DUMB | 2465.483 |
0 | MCBLOCK | 3248.863 |
1 | MCBLOCK | 3172.589 |
2 | MCBLOCK | 3161.555 |
3 | MCBLOCK | 3175.611 |
4 | MCBLOCK | 3184.713 |
5 | MCBLOCK | 3174.603 |
6 | MCBLOCK | 3164.557 |
7 | MCBLOCK | 3170.577 |
8 | MCBLOCK | 3166.561 |
9 | MCBLOCK | 3188.776 |
Gnuplot code to plot the results of the above command.
set key right bottom Left set grid set title "mbw results" set xlabel "Attempt" set ylabel "Bandwidth [MiB/s]" set style data lp set yrange [0:] plot "< grep MEMCPY ".data using 1:3 title "MEMCPY", \ "< grep DUMB ".data using 1:3 title "DUMB", \ "< grep MCBLOCK ".data using 1:3 title "MCBLOCK"
Properties
- «C-c C-x p»
- Key-value přiřazené k nadpisu
- Může měnit různé nastavení pro danou sekci
- Lze používat i jako jednoduchou databázi (hledání podle properties apod.)
- Column view «C-c C-x C-c»
I started using KiCad (version 4.0.1) for electronic design. It seems to be a great tool, but working with big connectors in schema editor is tedious. All connections have to be done manually and thus the process is error prone. Some way of automating the process would help. KiCad comes with scripting support, but unfortunately only in pcbnew. Eeschema seems not to have any support for automation yet. Hopefully, one can use xdotool under Linux to automate some boring tasks.
I wanted to attach the same labels to FMC connector pins as on the MicroZed FMC Carrier board – there is about 70 pins used. My initial state was this:
I copied the pin names and net labels from the original schmatic in PDF and put together the script bellow, which takes care of attaching the labels to the right pins. So after a few seconds I got the following:
The Python script that does the magic is here:
#!/usr/bin/env python3 import subprocess conn = [ ("LA06_P", "C10"), ("LA06_N", "C11"), ("LA10_P", "C14"), ("LA10_N", "C15"), ("LA14_P", "C18"), ("LA14_N", "C19"), ("LA18_CC_P", "C22"), ("LA18_CC_N", "C23"), ("LA27_P", "C26"), ("LA27_N", "C27"), ("LA01_CC_P", "D08"), ("LA01_CC_N", "D09"), ("LA05_P", "D11"), ("LA05_N", "D12"), ("LA09_P", "D14"), ("LA09_N", "D15"), ("LA13_P", "D17"), ("LA13_N", "D18"), ("LA17_CC_P", "D20"), ("LA17_CC_N", "D21"), ("LA23_P", "D23"), ("LA23_N", "D24"), ("LA26_P", "D26"), ("LA26_N", "D27"), ("CLK1_M2C_P", "G02"), ("CLK1_M2C_N", "G03"), ("LA00_CC_P", "G06"), ("LA00_CC_N", "G07"), ("LA03_P", "G09"), ("LA03_N", "G10"), ("LA08_P", "G12"), ("LA08_N", "G13"), ("LA12_P", "G15"), ("LA12_N", "G16"), ("LA16_P", "G18"), ("LA16_N", "G19"), ("LA20_P", "G21"), ("LA20_N", "G22"), ("LA22_P", "G24"), ("LA22_N", "G25"), ("LA25_P", "G27"), ("LA25_N", "G28"), ("LA29_P", "G30"), ("LA29_N", "G31"), ("LA31_P", "G33"), ("LA31_N", "G34"), ("LA33_P", "G36"), ("LA33_N", "G37"), ("CLK0_M2C_P", "H04"), ("CLK0_M2C_N", "H05"), ("LA02_P", "H07"), ("LA02_N", "H08"), ("LA04_P", "H10"), ("LA04_N", "H11"), ("LA07_P", "H13"), ("LA07_N", "H14"), ("LA11_P", "H16"), ("LA11_N", "H17"), ("LA15_P", "H19"), ("LA15_N", "H20"), ("LA19_P", "H22"), ("LA19_N", "H23"), ("LA21_P", "H25"), ("LA21_N", "H26"), ("LA24_P", "H28"), ("LA24_N", "H29"), ("LA28_P", "H31"), ("LA28_N", "H32"), ("LA30_P", "H34"), ("LA30_N", "H35"), ("LA32_P", "H37"), ("LA32_N", "H38"), ] subprocess.call(["xdotool", "search", "--name", "/FMC/", "windowfocus"]) xtab = str.maketrans({"_": "underscore"}) for net in conn: label = [char.translate(xtab) for char in net[0]] pin = [char.translate(xtab) for char in net[1]] subprocess.call(["xdotool", "key", "--delay", "50", "ctrl+f"] + pin + ["Return", "Escape", "Down", "Left", "Left", "Left", "w", "Left", "Left", "Left", "Left", "Left", "Left", "Left", "Left", "Left", "Left", "k", "l"] + label + [ "Return", "Return"])
Osnova, podle které jsem jel na dnešním workshopu na Installfestu.
Obsah
- 1. Co je Emacs?
- 2. Terminologie
- 3. Základní klávesové zkratky
- 4. Příkazová řádka
- 5. Velké (major) a malé (minor) módy
- 6. Přístup k nápovědě
- 7. Bloky (region, rectangle)
- 8. Správa oken a bufferů
- 9. Užitečné příkazy/klávesové zkratky
- 10. Konfigurace, “Customization”
- 11. File/directory-local variables
- 12. Programování
- 13. Užitečné módy
- 14. emacsclient
- 15. Úvod do Emacs Lispu
- 16. Příklad použití elispu
- 17. In-line elisp
1. Co je Emacs?
- Všestranný textový editor
- Interpret Lispu (v jazyce C) + spousta Lispového kódu
- C: 280 kLoC (20%), Lisp: 1 MLoC (80%)
- Srovnání – Firefox: 6 MLoC C/C++, 3.6 MLoC JavaScript+HTML
- Emacs = Editor MACroS nebo Esc-Meta-Alt-Ctrl-Shift :)
- Plnohodnotný operační systém :) (
M-x tetris
,M-x doctor
) - Začal vznikat v 70. letech
2. Terminologie
- Poplatná době vzniku
- Buffer = otevřený soubor
- Okno (window) = část obrazovky editoru zobrazující buffer
- Jedno okno zobrazuje právě jeden buffer
- Jeden buffer může být zobrazován nula až N okny
- Frame = to čemu dneska říkáme okno
- Může být grafický nebo textový (terminál)
3. Základní klávesové zkratky
- Mnoho jich je stejných jako v bashi
- Dobře se používají i na exotických klávesnicích (kámošův notebook, BT klávesnice k mobilu/tabletu, …)
- Notace: C = Control, M = Meta = Alt = Esc, S = Shift
3.1. Kurzor
- C-b = backward char, C-f = forward char, C-p = prev line, C-n = next line
- M-b = backward word, M-f = forward word, M-p = prev ???, M-n = next ???
- C-a = home, C-e = end
- M-a = backward sentence, M-e = forward sentence
3.2. Mazání
- C-d = znak, M-d = slovo
- C-k = do konce řádky
3.3. Příkazy
- C-x C-f = find (open) file
- C-x C-s = save file
- C-x C-c = “exit”
- C-x u, C-_, C-/ = undo
Pozn.: C-x je tzv. prefixová klávesa, podobně jako Esc
- C-l = redisplay, center, …
- C-g = přeruší právě vykonávanou operaci (mačkat, když Emacs nereaguj)
3.4. Hledání
- C-s = interactive search, C-M-s = interactive regexp search
- C-r = reverse search
3.5. Prefix/numeric argument
- Neplést s prefixovou klávesou
- Mnohým příkazům (klávesovým zkratkám) lze předat číselný parametr
- Většinou to znamená opakování
- C-u 8 C-f – posun o 8 znaků doprava
- M-8 C-f – to samé
- C-u samotné modifikuje některé příkazy i bez čísla (C-u C-x C-c = vše ulož a “exit”)
4. Příkazová řádka
- M-x <příkaz>
- Mini-buffer – většina klávesových zkratek stejná jako při editaci normálních bufferů (souborů)
- tab-completion
- completion “modes”
- Příkaz je lispovská funkce označená jako
(interactive)
. - Klávesové zkratky spouští příkazy – viz
(global-set-key ...)
.
5. Velké (major) a malé (minor) módy
- V Emacsu se vše motá kolem “módů”
- Velký mód:
- definuje zvýrazňování syntaxe,
- definuje klávesové zkratky,
- implementuje (automatické) zarovnávání kódu,
- vybírá se automaticky podle přípony nebo obsahu souboru,
- lze ho vybrat i manuálně (spuštěním příkazu
*-mode
; např.c-mode
).
- Malý mód:
- Implementuje dodatečnou funkcionalitu, kterou má smysl používat s vícero velkými módy.
- Příklady:
- flyspell-mode
- auto-fill-mode
- hide-show-mode
- Jaké módy jsou momentálně aktivní naznačuje Mode line.
6. Přístup k nápovědě
- Emacs má poměrně dobrý systém nápovědy.
- C-h prefix key
- C-h f – funkce
- C-h v – proměnné
- C-h k – klávesová zkratka
- C-h m – mód
- C-h i – prohlížeč info stránek (C-h i m Emacs <RET>)
- Navigace: ‘n’, ‘p’, ’[’, ’]’
- ’i’ – hledání v rejstříku (pak ’,’)
M-x man
7. Bloky (region, rectangle)
- Nové verze Emacsu (konečně) podporují výběr pomocí S-<šipky>.
- Tradičně: blok je oblast od “značky” ke kurzoru (point).
- C-SPC = polož značku
- Ctrl-C, Ctrl-V, Ctrl-X – standardně nefunguje, lze zapnout
M-x cua-mode
.- Ctrl-C koliduje s mnoha standardními zkratkami; cua-mode to částečně řeší.
- Tradičně:
- Smazaný text se ukládá do “kill ringu” (např. C-k, M-d)
- C-y (yank) vloží hodnotu z konce “kill ringu”
- M-y (následující po C-y) vkládá starší hodnoty z “kill ringu”.
- C-w = kill region
- M-w = “copy” region
- Obdélníkové bloky
- C-x r * – neintuitivní (aspoň pro mne)
- C-x SPC = rectangle mark mode
M-x string-insert-rectangle
– vloží stejný text na každou řádku bloku
- CUA mode: C-RET = cua-set-rectangle-mark
- string-insert-rectangle není potřeba; stačí začít psát
- ve výjimečných případech se chová podivně
8. Správa oken a bufferů
- Správa oken
- není ideální
- C-x 2, C-x 3 = rozděl okno vertikálně/horizontálně
- C-x o = přesun na následující okno
- Windmove package – pohyb mezi okny podle směru (např. S-<šipky>)
- C-x 0 = smaž aktuální okno (ale ne buffer)
- C-x 1 = smaž ostatní okna
- Přepínání bufferů
- C-x <left>/<right>
- C-x b = zadat název bufferu (použitelné s completion módy)
- C-x C-b (polo) interaktivní výběr bufferu
- M-x ibuffer = interaktivní výběr bufferu
- M-x helm-buffer-list = dtto
9. Užitečné příkazy/klávesové zkratky
- M-q = přeformátování odstavce (v mnoha módech inteligentní)
- C-s = interactive search, C-M-s = interactive regexp search
- V příkazové řádce hledání:
- C-s – minulé hledání
- C-w – doplní slovo pod kurzorem
- M-c – přepne rozlišování malých a velkých písmen
- M-e – editace (např. minulého hledání po C-s C-s)
- V příkazové řádce hledání:
- M-% = nahrazení řetězce
- C-M-S-% = nahrazení regulárního výrazu
- M-/ = doplň rozepsané slovo podle předchozích slov
- Macros: F3 = začátek nahrávání, F4 = konec nahrávání/spuštění
- Nahrazení textu ve víc souborech najednou:
M-x dired-mode
, mark (m
),Q
M-x occur
M-x rgrep
- M-; comment-dwim (do what I mean)
- C-M-a = beginning-of-defun, C-M-e = end-of-defun
- C-M-p, C-M-n, C-M-u = pohyb po závorkami ohraničených blocích (prev, next, up)
- C-u C-SPC – návrat na místa předchozí editace
10. Konfigurace, “Customization”
- Možnosti konfigurace jsou nekonečné
- Předkonfigurovaný Emacs: Emacs Prelude
- Standardní konfigurační soubor
~/.emacs
nebo~/.emacs.d/init.el
.- Nastavování proměnných
- Konfigurace klávesových zkratek
(global-set-key (kbd "C-c w") 'toggle-truncate-lines)
- Definice vlastních příkazů
- Zapínání minor módu
- Customization
UserHacker-friendly konfigurace- +GUI+TUI pro konfiguraci skoro všeho
M-x customize
M-x
customize-{variable,face,group}- Není potřeba ručně editovat
~/.emacs
11. File/directory-local variables
- Konfiguraci Emacsu lze ukládat i do editovaných souborů.
- Podobně je možné konfiguraci uložit do souboru
.dir-locals.el
a pak bude platit pro všechny soubory v daném adresáři a jeho podadresářích. M-x add-file-local-variable
M-x add-dir-local-variable
/* Local Variables: */ /* compile-command: "make CFLAGS='-g -O0 -Wall" */ /* End: */
12. Programování
- Odsazování
- většinou automatické, nebo po <TAB>
- inteligentní zarovnávání všeho
- ’M-q’ v komentáři zarovná komentář
- Kompilace
- M-x compile, M-x recompile
- M-x next-error (skáče na chyby, detekce mnoha kompilátorů/formátů chybových hlášení)
- Doplňování kódu
- auto-complete-mode
- company-mode (asi lepší)
- yasnippet (TextMate snippets in Emacs)
- Často možnost interakce s interpretrem skriptovacích jazyků (např. v
M-x python-shell-send-defun
) - Verzovací systémy
vc
– stejné klávesové zkratky pro všechny VCS (např.C-x v =
– diff aktuálního souboru)- magit – speciální mód pro práci s gitem
13. Užitečné módy
- auctex – pokročilý editor na *TeXové dokumenty
- navigace po sekcích, promote/demote sekcí
- integrace s BibTeXem pro snadné hledání/vkládání citací
- náhledy rovnic a obrázků přímo v editovaném textu
- org-mode – tvorba a organizování poznámek, TODO seznamů, plánování
projektu, tvorba dokumentů atd.
- tato prezentace je v org módu
- dired-mode – správa souborů
- C-x d, C-x C-f (adresář)
- mazání souborů: označit ‘d’, smazat ‘x’
- TRAMP
- vzdálená editace (kompilace, …) souborů
- SSH, sudo, …
- notmuch – lokální “gmail” (rychlé vyhledávání), GUI v Emacsu
- shell, eshell – práce s příkazovou řádkou bez opuštění Emacsu
Instalace balíků třetích stran:
M-x list-packages
- MELPA repozitář balíků
14. emacsclient
- Emacs většinou dlouho startuje
- Doba startu záleží na uživatelské konfiguraci
- Inicializace balíků při startu vs. autoload
- Emacs lze pustit jako “server” (
emacs --daemon
) a připojovat se k němu pomocí programuemacsclient
.Nic se nemusí konfigurovat, emacsclient si spustí emacs sám:
#!/bin/sh exec emacsclient -a '' "$@"
- K jednomu serveru se lze připojit současně z různých terminálů (lokálně X-windows, vzdáleně přes SSH).
15. Úvod do Emacs Lispu
- (Emacs) Lisp
- C-h i m Elisp <RET>
- Je jednodušší než např. Common Lisp
- Program i data vypadají stejně (S-výrazy/S-expressions/sexp)
- Vyhodnocení výrazu:
- číslo je číslo, řetězec je řetězec
seznam: první prvek udává jméno funkce, ostatní prvky jsou parametry.
(message "Ahoj") (message (concat "Ahoj" "Installfest"))
- Proměnné:
globální:
(defvar xyz 0)
lokální:
(let (a b) <kód>)
Funkce:
(defun fs-czech () "Starts flyspell with czech dictionary" (interactive) ; Způsobí, že fs-czech se dá spustit pomocí M-x (flyspell-mode) (ispell-change-dictionary "czech") (flyspell-buffer))
16. Příklad použití elispu
Navigace po framech v LaTeX beameru
(defconst latex-beamer-frame-re ; Regulární výraz, který budeme hledat "\\\\\\(frametitle\\|section\\){") ; '\' se musí 2x escapovat (defun is-outside-of-comment () (null (nth 8 (syntax-ppss)))) (defun latex-beamer-previous-frame () (interactive) (while (progn (re-search-backward latex-beamer-frame-re) (not (is-outside-of-comment)))) (recenter 0)) (defun latex-beamer-next-frame () (interactive) (when (looking-at-p latex-beamer-frame-re) (forward-char)) (while (progn (re-search-forward latex-beamer-frame-re) (not (is-outside-of-comment)))) (goto-char (match-beginning 0)) (recenter 0)) (add-hook 'LaTeX-mode-hook (lambda () (local-set-key (kbd "M-p") 'latex-beamer-previous-frame) (local-set-key (kbd "M-n") 'latex-beamer-next-frame)))
17. In-line elisp
- C-x C-e = vyhodnoť výraz před kurzorem (point)
- Kusy elispu lze vkládat do komentářů programů v jiných jazycích a spouštět přímo tam.
\chapter*{List of Acronyms} % Sort acronyms: (let ((sort-fold-case t)) (sort-regexp-fields nil "^[[:space:]]*\\\\acro\{\\([^}]*\\)\}.*$" "\\1" (search-forward "\\begin{acronym}") (search-forward "\\end{acronym}"))) \begin{acronym}[XXXXX] \acro{AC}{Access Category} \acro{ACK}{Acknowledge} \acro{BFQ}{Budget Fair Queuing} \end{acronym}
Stejně jako vloni jsem měl i letos přednášku na InstallFestu. Tentokrát to bylo o nástroji novaboot, který už přes dva roky vyvíjím a používám jej k mnoha zajímavým věcem. Některé z nich jsem během přednášky zmínil a najdete je ve slidech.
Při přednášce se dostavil klasický “demo efekt”, tedy že to, co ještě ráno fungovalo, fungovat přestalo. Nemohl za to novaboot, ale pochybná implementace technologie Intel AMT na mém počítači. Naštěstí jsem měl ještě jeden počítač, se kterým novaboot fungoval, ale bohužel jsem na něj neměl otočenou web kameru, takže se návštěvníci museli spokojit jen s výstupem na mém terminálu.