aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/_posts
diff options
context:
space:
mode:
authorEgor Tensin <egor@tensin.name>2026-06-06 22:23:54 +0200
committerEgor Tensin <egor@tensin.name>2026-06-06 22:24:45 +0200
commitbe5e0048913797f2ef91065908730da025113c34 (patch)
treedd16e4908bb93953dbc823d7624f76c363a00bf4 /_posts
parentbump dependencies (diff)
downloadblog-be5e0048913797f2ef91065908730da025113c34.tar.gz
blog-be5e0048913797f2ef91065908730da025113c34.zip
move Jekyll source files to src/
Diffstat (limited to '_posts')
-rw-r--r--_posts/2015-07-03-std-call-once-bug.md252
-rw-r--r--_posts/2017-01-07-building-boost.md265
-rw-r--r--_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md273
-rw-r--r--_posts/2018-02-18-peculiar-indentation.md101
-rw-r--r--_posts/2020-02-24-ssh-tunnel-windows.md153
-rw-r--r--_posts/2020-05-06-docker-bind-mounts.md227
-rw-r--r--_posts/2020-05-20-makefile-escaping.md439
-rw-r--r--_posts/2021-03-10-ubuntu-packaging.md320
-rw-r--r--_posts/2022-09-07-gdb-sleep-all.md33
-rw-r--r--_posts/2022-11-07-ptrace-sigtraps.md72
-rw-r--r--_posts/2022-11-07-ptrace-waitpid.md51
-rwxr-xr-x_posts/snippets/gdb_sleep_all/gdb_sleep_all.sh17
-rw-r--r--_posts/snippets/gdb_sleep_all/sleep.gdb2
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/shared.hpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.cpp11
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/main.cpp13
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.cpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/main.cpp8
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/shared.hpp12
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/main.cpp10
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.cpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/shared.hpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/main.cpp10
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.cpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/shared.hpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/main.cpp10
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.cpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/shared.hpp10
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.cpp19
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/main.cpp22
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.cpp15
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/main.cpp18
-rw-r--r--_posts/snippets/ubuntu_packaging/basic/changelog5
-rw-r--r--_posts/snippets/ubuntu_packaging/basic/control13
-rw-r--r--_posts/snippets/ubuntu_packaging/basic/copyright31
-rw-r--r--_posts/snippets/ubuntu_packaging/basic/rules3
-rw-r--r--_posts/snippets/ubuntu_packaging/gbp/gbp.conf5
-rw-r--r--_posts/snippets/ubuntu_packaging/install/test.install1
45 files changed, 0 insertions, 2484 deletions
diff --git a/_posts/2015-07-03-std-call-once-bug.md b/_posts/2015-07-03-std-call-once-bug.md
deleted file mode 100644
index 8191ad3..0000000
--- a/_posts/2015-07-03-std-call-once-bug.md
+++ /dev/null
@@ -1,252 +0,0 @@
----
-title: std::call_once bug in Visual C++ 2012/2013
-category: C++
----
-I've recently come across a nasty standard library bug in the implementation
-shipped with Microsoft Visual Studio 2012/2013.
-[StackOverflow was of no help], so I had to somehow report the bug to the
-maintainers.
-Oddly enough, Visual Studio's [Connect page] wouldn't let me report one,
-complaining about the lack of permissions, even though I was logged in from my
-work account, associated with my Visual Studio 2013 installation.
-
-Fortunately, I've come across the personal website of this amazing guy,
-[Stephan T. Lavavej], who appears to be the chief maintainer of Microsoft's
-standard library implementation.
-He seems to be your go-to guy when it comes to obvious standard library
-misbehaviours.
-
-[StackOverflow was of no help]: https://stackoverflow.com/questions/26477070/concurrent-stdcall-once-calls
-[Connect page]: https://connect.microsoft.com/VisualStudio
-[Stephan T. Lavavej]: http://nuwen.net/stl.html
-
-C++11 and singletons
---------------------
-
-Anyway, the story begins with me trying to implement the singleton pattern
-using C++11 facilities like this:
-
-```c++
-#include <mutex>
-
-template <typename Derived>
-class Singleton {
-public:
- static Derived& get_instance() {
- std::call_once(initialized_flag, &initialize_instance);
- return Derived::get_instance_unsafe();
- }
-
-protected:
- Singleton() = default;
- ~Singleton() = default;
-
- static Derived& get_instance_unsafe() {
- static Derived instance;
- return instance;
- }
-
-private:
- static void initialize_instance() {
- Derived::get_instance_unsafe();
- }
-
- static std::once_flag initialized_flag;
-
- Singleton(const Singleton&) = delete;
- Singleton& operator=(const Singleton&) = delete;
-};
-
-template <typename Derived>
-std::once_flag Singleton<Derived>::initialized_flag;
-```
-
-Neat, huh?
-Now other classes can inherit from `Singleton`, implementing the singleton
-pattern effortlessly:
-
-```c++
-class Logger : public Singleton<Logger> {
-private:
- Logger() = default;
- ~Logger() = default;
-
- friend class Singleton<Logger>;
-};
-```
-
-Note that the [N2660] standard proposal isn't/wasn't implemented in the
-compilers shipped with Visual Studio 2012/2013.
-If it was, I wouldn't, of course, need to employ this `std::call_once`
-trickery, and the implementation would be much simpler, i.e. something like
-this:
-
-```c++
-class Logger {
-public:
- static Logger& get_instance() {
- static Logger instance;
- return instance;
- }
-
-private:
- Logger() = default;
- ~Logger() = default;
-};
-```
-
-<div class="alert alert-info" markdown="1">
-
-The point is that the `Logger::get_instance` routine above wasn't thread-safe
-until C++11.
-Imagine what might happen if `Logger`'s constructor takes some time to
-initialize the instance.
-If a couple of threads then call `get_instance`, the first thread might begin
-the initialization process, making the other thread believe that the instance
-had already been intialized.
-This other thread might then return a reference to the instance which hasn't
-yet completed its initialization and is most likely unsafe to use.
-
-Since C++11 includes the proposal mentioned above, this routine would indeed be
-thread-safe in C++11.
-Unfortunately, the compilers shipped with Visual Studio 2012/2013 don't/didn't
-implement this particular proposal, which caused me to look at
-`std::call_once`, which seemed to implement exactly what I needed.
-
-</div>
-
-[N2660]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm
-
-Problem
--------
-
-Unfortunately, matters became a bit more complicated when I tried to introduce
-two singletons, one having a dependency on the other.
-I had `Logger`, like in the example above, and some kind of a "master"
-singleton (let's call it `Duke`).
-`Duke`'s constructor was complicated and time-consuming, and definitely
-required some logging to be done.
-I thought that I could simply call `Logger::get_instance` inside `Duke`'s
-constructor, and everything looked fine at first glance.
-
-```c++
-#include <chrono>
-#include <thread>
-
-class Logger : public Singleton<Logger> {
-public:
- Logger& operator<<(const char* msg) {
- // Actual logging is stripped for brevity.
- return *this;
- }
-
-private:
- Logger() {
- // Opening log files, etc.
- std::this_thread::sleep_for(std::chrono::seconds{3});
- }
-
- ~Logger() = default;
-
- friend class Singleton<Logger>;
-};
-
-class Duke : public Singleton<Duke> {
-private:
- Duke() {
- Logger::get_instance() << "started Duke's initialization";
- // It's a lot of work to be done.
- std::this_thread::sleep_for(std::chrono::seconds{10});
- Logger::get_instance() << "finishing Duke's initialization";
- }
-
- ~Duke() = default;
-
- friend class Singleton<Duke>;
-};
-```
-
-Now, what happens if I have two threads, one using the `Duke` instance, and the
-other logging something?
-Like in this example:
-
-```c++
-#include <thread>
-
-namespace {
-
-void get_logger() {
- entered(__FUNCTION__);
- Logger::get_instance();
- exiting(__FUNCTION__);
-}
-
-void get_duke() {
- entered(__FUNCTION__);
- Duke::get_instance();
- exiting(__FUNCTION__);
-}
-
-}
-
-int main() {
- std::thread t1{&get_duke};
- std::thread t2{&get_logger};
- t1.join();
- t2.join();
- return 0;
-}
-```
-
-`entered` and `exiting` are utility functions to print timestamps.
-The implementation is included in the [complete code sample].
-{: .alert .alert-info }
-
-The first thread is supposed to have the total running time of about 13
-seconds, right?
-Three seconds to initialize the `Logger` instance and ten to initialize the
-`Duke` instance.
-The second thread, similarly, is supposed to be done in about 3 seconds
-required for the initialization of `Logger`.
-
-Weirdly, this program produces the following output when compiled using Visual
-Studio 2013's compiler:
-
- Entered `anonymous-namespace'::get_duke at Fri Jul 03 02:26:16 2015
- Entered `anonymous-namespace'::get_logger at Fri Jul 03 02:26:16 2015
- Exiting `anonymous-namespace'::get_duke at Fri Jul 03 02:26:29 2015
- Exiting `anonymous-namespace'::get_logger at Fri Jul 03 02:26:29 2015
-
-Isn't it wrong that the second thread actually took the same 13 seconds as the
-first thread?
-Better check with some other compiler in case it was me who made a mistake.
-Unfortunately, the program behaves as expected when compiled using GCC:
-
- Entered get_logger at Fri Jul 3 02:27:12 2015
- Entered get_duke at Fri Jul 3 02:27:12 2015
- Exiting get_logger at Fri Jul 3 02:27:15 2015
- Exiting get_duke at Fri Jul 3 02:27:25 2015
-
-So it appears that the implementation of `std::call_once` shipped with Visual
-Studio 2012/2013 relies on some kind of a global lock, which causes even the
-simple example above to misbehave.
-
-The [complete code sample] to demonstrate the misbehaviour described above can
-be found in this blog's repository.
-
-[complete code sample]: {{ site.github.repository_url }}/tree/master/std_call_once_bug
-
-Conclusion
-----------
-
-So, since I couldn't submit the bug via Visual Studio's [Connect page], I wrote
-to Mr. Lavavej directly, not hoping for an answer.
-Amazingly, it took him less than a day to reply.
-He told me he was planning to overhaul `std::call_once` for Visual Studio 2015.
-Meanwhile, I had to stick to something else; I think I either dropped logging
-from `Duke`'s constructor or initialized all the singleton instances manually
-before actually using any of them.
-In a few months, Mr. Lavavej replied to me that the bug has been fixed in
-Visual Studio 2015 RTM.
-I would like to thank him for the professionalism and responsibility he's
-shown.
diff --git a/_posts/2017-01-07-building-boost.md b/_posts/2017-01-07-building-boost.md
deleted file mode 100644
index cddba13..0000000
--- a/_posts/2017-01-07-building-boost.md
+++ /dev/null
@@ -1,265 +0,0 @@
----
-title: Building Boost on Windows
-category: C++
----
-Below you can find the steps required to build Boost libraries on Windows.
-These steps tightly fit my typical workflow, which is to use Boost libraries in
-CMake builds using either Visual Studio or the combination of Cygwin +
-MinGW-w64.
-I would expect, however, that the procedure for the latter toolset can easily
-be adjusted for generic GCC distributions (including vanilla GCCs found in
-popular Linux distributions).
-
-One of the features of this workflow is that I build throwaway, "run
-everywhere, record the results, and scrap it" executables more often than not,
-so I prefer to link everything statically, including, for instance, C/C++
-runtimes.
-This is implemented by passing `runtime-link=static` to Boost's build utility
-`b2`; change this to `runtime-link=dynamic` to link the runtime dynamically.
-
-Excerpts from shell sessions in this post feature a few different commands
-besides Boost's `b2` and `cmake`, like `cd` and `cat`.
-They are used to hint at my personal directory layout, display various
-auxiliary files, etc.
-Windows' `cd`, for example, simply prints the current working directory;
-Cygwin's `pwd` serves the same purpose.
-`cat` is used to display files.
-
-Visual Studio
--------------
-
-Statically-linked Boost libraries are built, both the debug and the release
-versions of them (these are default settings).
-While it is required to keep x86 and x64 libraries in different directories (to
-avoid file name clashes), it's not necessary to separate debug libraries from
-their release counterparts, because that information is actually encoded in
-file names (the "gd" suffix).
-
-### x86
-
-{% capture out1 %}
-D:\workspace\third-party\boost_1_61_0\msvc
-{% endcapture %}
-
-{% capture cmd3 %}
-b2 --stagedir=stage\x86 ^
- runtime-link=static ^
- --with-filesystem ^
- --with-program_options ^
- ...
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='cd' out=out1 %}
-{% include jekyll-theme/shell.html cmd='bootstrap' %}
-{% include jekyll-theme/shell.html cmd=cmd3 %}
-
-### x64
-
-The only important difference is that you have to pass `address-model=64` to
-`b2` (notice also the different "staging" directory).
-
-{% capture out1 %}
-D:\workspace\third-party\boost_1_61_0\msvc
-{% endcapture %}
-
-{% capture cmd3 %}
-b2 --stagedir=stage\x64 ^
- runtime-link=static ^
- address-model=64 ^
- --with-filesystem ^
- --with-program_options ^
- ...
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='cd' out=out1 %}
-{% include jekyll-theme/shell.html cmd='bootstrap' %}
-{% include jekyll-theme/shell.html cmd=cmd3 %}
-
-Cygwin + MinGW-w64
-------------------
-
-Contrary to the Visual Studio example above, it is required to store debug and
-release libraries *as well as* x86 and x64 libraries in different directories.
-It is required to avoid file name clashes; unlike the Visual Studio "toolset"
-(in Boost's terms), GCC-derived toolsets don't encode any information (like
-whether the debug or the release version of a library was built) in file names.
-
-Also, linking the runtime statically doesn't really make sense for MinGW, as it
-always links to msvcrt.dll, which is [simply the Visual Studio 6.0 runtime].
-
-[simply the Visual Studio 6.0 runtime]: https://sourceforge.net/p/mingw-w64/wiki2/The%20case%20against%20msvcrt.dll/
-
-In the examples below, only the debug versions of the libraries are built.
-Build the release versions by executing the same command, and substituting
-`variant=release` instead of `variant=debug` and either
-`--stagedir=stage/x86/release` or `--stagedir=stage/x64/release`, depending
-on the target architecture.
-
-### x86
-
-{% capture out1 %}
-/cygdrive/d/workspace/third-party/boost_1_61_0/mingw
-{% endcapture %}
-
-{% capture out3 %}
-using gcc : : i686-w64-mingw32-g++ ;
-{% endcapture %}
-
-{% capture cmd4 %}
-./b2 toolset=gcc-mingw \
- target-os=windows \
- link=static \
- variant=debug \
- --stagedir=stage/x86/debug \
- --user-config=user-config-x86.jam \
- --with-filesystem \
- --with-program_options \
- ...
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='pwd' out=out1 %}
-{% include jekyll-theme/shell.html cmd='./bootstrap.sh' %}
-{% include jekyll-theme/shell.html cmd='cat user-config-x86.jam' out=out3 %}
-{% include jekyll-theme/shell.html cmd=cmd4 %}
-
-The "user" configuration file above stopped working at some point; not sure as
-to who's to blame, Cygwin or Boost.
-If you see something like "`error: provided command 'i686-w64-mingw32-g++' not
-found`", add ".exe" to the binary name above, so that the whole file reads
-"`using gcc : : i686-w64-mingw32-g++.exe ;`".
-{: .alert .alert-info }
-
-### x64
-
-Notice the two major differences from the x86 example:
-
-* the addition of `address-model=64` (as in the example for Visual Studio),
-* the different "user" configuration file, pointing to `x86_64-w64-mingw32-g++`
-instead of `i686-w64-mingw32-g++`.
-
-Again, as in the example for Visual Studio, a different "staging" directory
-needs to be specified using the `--stagedir` parameter.
-
-{% capture out1 %}
-/cygdrive/d/workspace/third-party/boost_1_61_0/mingw
-{% endcapture %}
-
-{% capture out3 %}
-using gcc : : x86_64-w64-mingw32-g++ ;
-{% endcapture %}
-
-{% capture cmd4 %}
-./b2 toolset=gcc-mingw \
- address-model=64 \
- target-os=windows \
- link=static \
- variant=debug \
- --stagedir=stage/x64/debug \
- --user-config=user-config-x64.jam \
- --with-filesystem \
- --with-program_options \
- ...
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='pwd' out=out1 %}
-{% include jekyll-theme/shell.html cmd='./bootstrap.sh' %}
-{% include jekyll-theme/shell.html cmd='cat user-config-x64.jam' out=out3 %}
-{% include jekyll-theme/shell.html cmd=cmd4 %}
-
-The "user" configuration file above stopped working at some point; not sure as
-to who's to blame, Cygwin or Boost.
-If you see something like "`error: provided command 'x86_64-w64-mingw32-g++'
-not found`", add ".exe" to the binary name above, so that the whole file reads
-"`using gcc : : x86_64-w64-mingw32-g++.exe ;`".
-{: .alert .alert-info }
-
-Usage in CMake
---------------
-
-### Visual Studio
-
-Examples below apply to Visual Studio 2015.
-You may want to adjust the paths.
-
-#### x86
-
-{% capture out1 %}
-D:\workspace\build\test_project\msvc\x86
-{% endcapture %}
-
-{% capture cmd2 %}
-cmake -G "Visual Studio 14 2015" ^
- -D BOOST_ROOT=D:\workspace\third-party\boost_1_61_0\msvc ^
- -D BOOST_LIBRARYDIR=D:\workspace\third-party\boost_1_61_0\msvc\stage\x86\lib ^
- -D Boost_USE_STATIC_LIBS=ON ^
- -D Boost_USE_STATIC_RUNTIME=ON ^
- ...
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='cd' out=out1 %}
-{% include jekyll-theme/shell.html cmd=cmd2 %}
-
-#### x64
-
-{% capture out1 %}
-D:\workspace\build\test_project\msvc\x64
-{% endcapture %}
-
-{% capture cmd2 %}
-cmake -G "Visual Studio 14 2015 Win64" ^
- -D BOOST_ROOT=D:\workspace\third-party\boost_1_61_0\msvc ^
- -D BOOST_LIBRARYDIR=D:\workspace\third-party\boost_1_61_0\msvc\stage\x64\lib ^
- -D Boost_USE_STATIC_LIBS=ON ^
- -D Boost_USE_STATIC_RUNTIME=ON ^
- ...
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='cd' out=out1 %}
-{% include jekyll-theme/shell.html cmd=cmd2 %}
-
-### Cygwin & MinGW-w64
-
-Examples below only apply to debug CMake builds.
-Notice that, contrary to the Visual Studio examples above, debug and release
-builds must be kept in separate directories.
-You may also want to adjust the paths.
-
-#### x86
-
-{% capture out1 %}
-/cygdrive/d/workspace/build/test_project/mingw/x86/debug
-{% endcapture %}
-
-{% capture cmd2 %}
-cmake -G "Unix Makefiles" \
- -D CMAKE_BUILD_TYPE=Debug \
- -D CMAKE_C_COMPILER=i686-w64-mingw32-gcc \
- -D CMAKE_CXX_COMPILER=i686-w64-mingw32-g++ \
- -D BOOST_ROOT=/cygdrive/d/workspace/third-party/boost_1_61_0/mingw \
- -D BOOST_LIBRARYDIR=/cygdrive/d/workspace/third-party/boost_1_61_0/mingw/stage/x86/debug/lib \
- -D Boost_USE_STATIC_LIBS=ON \
- ...
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='pwd' out=out1 %}
-{% include jekyll-theme/shell.html cmd=cmd2 %}
-
-#### x64
-
-{% capture out1 %}
-/cygdrive/d/workspace/build/test_project/mingw/x64/debug
-{% endcapture %}
-
-{% capture cmd2 %}
-cmake -G "Unix Makefiles" \
- -D CMAKE_BUILD_TYPE=Debug \
- -D CMAKE_C_COMPILER=x86_64-w64-mingw32-gcc \
- -D CMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++ \
- -D BOOST_ROOT=/cygdrive/d/workspace/third-party/boost_1_61_0/mingw \
- -D BOOST_LIBRARYDIR=/cygdrive/d/workspace/third-party/boost_1_61_0/mingw/stage/x64/debug/lib \
- -D Boost_USE_STATIC_LIBS=ON \
- ...
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='pwd' out=out1 %}
-{% include jekyll-theme/shell.html cmd=cmd2 %}
diff --git a/_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md b/_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md
deleted file mode 100644
index cb12867..0000000
--- a/_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md
+++ /dev/null
@@ -1,273 +0,0 @@
----
-title: static vs. inline vs. namespace&nbsp;{
-category: C++
-snippets_root_directory: snippets/static_vs_inline_vs_unnamed_namespaces
-snippets_language: c++
-snippets:
- static:
- - static/main.cpp
- - static/proxy.cpp
- - static/proxy.hpp
- - static/shared.hpp
- inline:
- - inline/shared.hpp
- inline_weird:
- - inline/weird/main.cpp
- - inline/weird/another.cpp
- - inline/weird/another.hpp
- unnamed_namespaces_weird:
- - unnamed_namespaces/weird/main.cpp
- - unnamed_namespaces/weird/another.cpp
- - unnamed_namespaces/weird/another.hpp
- unnamed_namespaces_ok:
- - unnamed_namespaces/ok/main.cpp
- - unnamed_namespaces/ok/another.cpp
- - unnamed_namespaces/ok/another.hpp
- static_and_inline:
- - static_and_inline/main.cpp
- - static_and_inline/proxy.cpp
- - static_and_inline/proxy.hpp
- - static_and_inline/shared.hpp
- unnamed_namespace_and_inline:
- - unnamed_namespace_and_inline/main.cpp
- - unnamed_namespace_and_inline/proxy.cpp
- - unnamed_namespace_and_inline/proxy.hpp
- - unnamed_namespace_and_inline/shared.hpp
- separate_method_definitions:
- - separate_method_definitions/main.cpp
- - separate_method_definitions/another.cpp
- - separate_method_definitions/another.hpp
- - separate_method_definitions/shared.hpp
----
-In this post I'll try to figure out whether I should use `static`, `inline` or
-unnamed namespaces for function definitions.
-
-TL;DR
------
-
-Here's my attempt to build an algorithm to decide whether a class/function
-should be defined with either of the `static`/`inline` specifiers or put into
-an unnamed namespace.
-The first question I answer is: is the entity defined in a header file or in a
-.cpp file?
-
-* **In a header** &mdash; Is it a class or a function?
- * **Class** &mdash; There's no need to do anything.
- * **Function** &mdash; Do you want it to behave differently for each
-translation unit (may be useful, for example, for logging)?
- * **Yes** &mdash; Use `static`.
- * **No** &mdash; Use `inline`.
-* **In a .cpp file** &mdash; Put it into an unnamed namespace.
-
-`static`
---------
-
-It's an old C-style method of defining functions in header files.
-This way, every translation unit gets its own copy of a function.
-What does that mean?
-The most obvious implication that pops into my head is that every local static
-variable defined inside that function gets an independent replica in every
-translation unit.
-For example, the program below would print
-
-```
-1
-1
-```
-
-due to the fact that both main.cpp and proxy.cpp get their own versions of `n`
-from `shared()`.
-
-{% include jekyll-theme/snippets/section.html section_id='static' %}
-
-In C, this is the only way to share function definitions between translation
-units (apart from the usual way of declaring a function in a header file and
-putting its definition to a .c file).
-
-### Properties
-
-* Using `static`, you can share function definitions between multiple
-translation units.
-* Each unit gets its own replica of the function: they have different
-addresses, their local static variables are independent, etc.
-* If different translation units define different functions with the same
-name using the `static` specifier, each unit can use its function without any
-issues.
-This might seem like an trivial claim, but other approaches sometimes disallow
-this, which is discussed below.
-
-`inline`
---------
-
-It's well-known that this keyword has pretty much nothing to do with whether a
-function will actually be inlined or not.
-It's used much more often to define functions in header files, since every
-function defined this way will be the same (as in "will have the same address")
-in every translation unit.
-Let's try and adjust the definition of `shared()` accordingly:
-
-{% include jekyll-theme/snippets/section.html section_id='inline' %}
-
-The same program would then print
-
-```
-1
-2
-```
-
-since both `main()` and `proxy()` would call the same `shared()`, incrementing
-the same `n`.
-
-Weird things happen when different translation units define different `inline`
-functions with the same name.
-
-{% include jekyll-theme/snippets/section.html section_id='inline_weird' %}
-
-According to my simple experiments, this program produces different output
-based on which .cpp file was specified first on the command line during
-compilation.
-For example, this is the output of test.exe produced with either `cl /W4 /EHsc
-main.cpp another.cpp /Fe:test.exe` or `g++ -Wall -Wextra -std=c++11 main.cpp
-another.cpp -o test.exe`.
-
-```
-main.cpp: shared()
-main.cpp: shared()
-```
-
-If we swap the order of .cpp files (`another.cpp main.cpp` instead of `main.cpp
-another.cpp`), the output becomes
-
-```
-another.cpp: shared()
-another.cpp: shared()
-```
-
-No warnings/errors are emitted, making the situation truly disturbing.
-I tested this with GNU compiler version 5.4.0 and Microsoft compiler version
-19.00.24210.
-
-This behavior can be easily fixed either by making these functions `static` or
-by using unnamed namespaces (see below).
-
-### Properties
-
-* Using `inline`, you can share function definitions between multiple
-translation units.
-* Each translation unit will use the same function: it will have the same
-address in every translation unit, its local static variables will be shared,
-etc.
-* Defining different `inline` functions with the same name in different
-translation units is undefined behavior.
-
-Two inline functions might be different even if they are the same textually.
-For example, they might reference two global variables which have the same
-name, but are defined in different translation units.
-{: .alert .alert-info }
-
-`namespace {`
--------------
-
-With respect to function definitions, unnamed namespaces are, according to my
-understanding, quite similar to the `static` keyword.
-The additional value they provide is that they provide a way to apply `static`
-not only to functions, but to classes also.
-Remember the weirdness that happens when multiple translation units define
-different `inline` functions with the same name?
-Arguably, it gets even worse if we add classes to the equation.
-
-{% include jekyll-theme/snippets/section.html section_id='unnamed_namespaces_weird' %}
-
-Compiling this program the same way we did in the `inline` example (`cl /W4
-/EHsc main.cpp another.cpp /Fe:test.exe`/`g++ -Wall -Wextra -std=c++11 main.cpp
-another.cpp -o test.exe`) yields different outputs depending on which .cpp file
-was specified first.
-
-```
-main.cpp: Test::Test()
-1
-main.cpp: Test::Test()
-```
-
-```
-another.cpp: Test::Test()
-1065353216
-another.cpp: Test::Test()
-```
-
-I'm not sure why anybody would want that.
-This can be easily fixed by putting both `Test` classes into unnamed
-namespaces.
-The program than reads
-
-{% include jekyll-theme/snippets/section.html section_id='unnamed_namespaces_ok' %}
-
-After the adjustment, it produces the same output regardless of compilation
-options.
-
-```
-main.cpp: Test::Test()
-1
-another.cpp: Test::Test()
-```
-
-Notice how sharing classes defined in header files isn't discussed here.
-The standard actually guarantees that if a class is defined in a header file,
-all translation units that use it share the definition.
-
-### Properties
-
-* Essentially, unnamed namespaces allow the `static` keyword to be applied to
-classes.
-* Similar to the `static` approach, each translation unit gets its own replica
-of a function/class, including their own local static variables, etc.
-* Defining different classes with the same name in different translation units
-(without utilizing unnamed namespaces) is undefined behavior.
-
-Tricky cases
-------------
-
-### `static` + `inline`
-
-In case a function is defined as `static inline`, `static` wins, and `inline`
-is ignored.
-The program below outputs
-
-```
-1
-1
-```
-
-{% include jekyll-theme/snippets/section.html section_id='static_and_inline' %}
-
-In general, I can't think of a reason to define a `static inline` function.
-
-### `namespace {` + `inline`
-
-If an `inline` function is defined in an unnamed namespace, the unnamed
-namespace wins.
-The program below outputs
-
-```
-1
-1
-```
-
-{% include jekyll-theme/snippets/section.html section_id='unnamed_namespace_and_inline' %}
-
-In general, I can't think of a reason to define an `inline` function in an
-unnamed namespace.
-
-### Separate method definitions
-
-If you want to separate your class declaration from its method definitions
-while keeping them in the same header file, each method must be explicitly
-defined `inline`.
-The program below outputs
-
-```
-1
-2
-```
-
-{% include jekyll-theme/snippets/section.html section_id='separate_method_definitions' %}
diff --git a/_posts/2018-02-18-peculiar-indentation.md b/_posts/2018-02-18-peculiar-indentation.md
deleted file mode 100644
index c477382..0000000
--- a/_posts/2018-02-18-peculiar-indentation.md
+++ /dev/null
@@ -1,101 +0,0 @@
----
-title: Peculiar Haskell indentation
-category: Haskell
----
-I've fallen into a Haskell indentation pitfall.
-I think it must be common, so I'm describing it here.
-
-The problem is that indentation rules in `do` blocks are not intuitive to me.
-For example, the following function is valid Haskell syntax:
-
-```haskell
-foo1 :: IO ()
-foo1 =
- alloca $ \a ->
- alloca $ \b ->
- alloca $ \c -> do
- poke a (1 :: Int)
- poke b (1 :: Int)
- poke c (1 :: Int)
- return ()
-```
-
-In fact, this funnier version is also OK:
-
-```haskell
-foo2 :: IO ()
-foo2 = alloca $ \a ->
- alloca $ \b ->
- alloca $ \c -> do
- poke a (1 :: Int)
- poke b (1 :: Int)
- poke c (1 :: Int)
- return ()
-```
-
-If you add an outer `do` however, things become a little more complicated.
-For example, this is the valid version of the functions above with an outer
-`do`:
-
-```haskell
-foo3 :: IO ()
-foo3 = do
- alloca $ \a ->
- alloca $ \b ->
- alloca $ \c -> do
- poke a (1 :: Int)
- poke b (1 :: Int)
- poke c (1 :: Int)
- return ()
-```
-
-Notice the extra indentation for each of the `alloca`s.
-When I tried to remove these seemingly excessive indents, GHC complained with
-the usual `parse error (possibly incorrect indentation or mismatched
-brackets)`.
-
-```haskell
-foo4 :: IO ()
-foo4 = do
- alloca $ \a ->
- alloca $ \b ->
- alloca $ \c -> do
- poke a (1 :: Int)
- poke b (1 :: Int)
- poke c (1 :: Int)
- return ()
-```
-
-The truth is, the rules for desugaring `do` blocks are surprisingly simple and
-literal.
-GHC inserts semicolons according to the rules [found in the Wikibook].
-So it inserts semicolons between the `alloca`s on the same level, so `foo4`
-becomes:
-
-```haskell
-foo4 :: IO ()
-foo4 = do
- { alloca $ \a ->
- ; alloca $ \b ->
- ; alloca $ \c -> do
- { poke a (1 :: Int)
- ; poke b (1 :: Int)
- ; poke c (1 :: Int)
- ; return ()
- }
- }
-```
-
-[found in the Wikibook]: https://en.wikibooks.org/wiki/Haskell/Indentation#Explicit_characters_in_place_of_indentation
-
-The semicolons after `->` are clearly invalid Haskell syntax, hence the error.
-
-P.S. To compile the functions above, you need to include them in a module and
-add proper imports, e.g.
-
-```haskell
-module PeculiarIndentation where
-
-import Foreign.Marshal.Alloc (alloca)
-import Foreign.Storable (poke)
-```
diff --git a/_posts/2020-02-24-ssh-tunnel-windows.md b/_posts/2020-02-24-ssh-tunnel-windows.md
deleted file mode 100644
index fdbc134..0000000
--- a/_posts/2020-02-24-ssh-tunnel-windows.md
+++ /dev/null
@@ -1,153 +0,0 @@
----
-title: Persistent SSH tunnel
----
-SSH tunneling is awesome.
-For some reason, I've only recently learned about this feature, but I've been
-immediately blown away by how useful it can be.
-
-Basically, to use SSH tunneling (a.k.a. port forwarding) you need to have a SSH
-client (`ssh`) with an access to a SSH server.
-You can then access any host your SSH server has access to.
-It works like this:
-
-* the client establishes a connection to the SSH server,
-* the client asks the server to forward incoming requests to the destination
-host,
-* the client listens on a proxy port on the local machine, and forwards
-requests to the SSH server.
-
-Say, you have access to SSH server `gateway` on port 22, and you want to gain
-access to HTTPS server `dest` on port 443, which is only accessible from the
-the SSH server.
-You can then run something like
-
-{% include jekyll-theme/shell.html cmd='ssh -L 4433:dest:443 gateway -p 22' %}
-
-And now you can access `dest` at `https://localhost:4433/`.
-That's brilliant, really.
-
-But there's more.
-You can make a _reverse_ tunnel, allowing you to give access to any host your
-client computer has access to, via a remote SSH server.
-It works like this:
-
-* your SSH client establishes a connection to the SSH server,
-* the client asks the server to listen on a port of your choosing and forward
-incoming requests to the client,
-* the client forwards incoming requests to the destination host.
-
-This, as I've recently learned, is a common pattern to subvert corporate
-firewalls, which frequently forbid incoming connections.
-Say, you want to access your work computer from home via RDP.
-Both your home and your work computers have access to a SSH server `gateway` on
-port 22 (you might want to change it to port 80 or 443 if your outside
-connections are filtered).
-
-You can then run something like (notice the `-R`)
-
-{% include jekyll-theme/shell.html cmd='ssh -R 13389:127.0.0.1:3389 gateway -p 22' %}
-
-and now you can connect to `gateway:13389` from your home computer using a RDP
-client.
-Even more brilliant!
-
-You might need to set the `GatewayPorts` setting to `yes` or `clientspecified`
-on your SSH server (typically in "/etc/ssh/sshd_config").
-
-Batch mode
-----------
-
-If you want to establish a reverse SSH tunnel automatically, some tweaking is
-required.
-First, set some SSH client options:
-
-* `-F /dev/null` to disregard the user config,
-* `-oBatchMode=yes` to run non-interactively,
-* `-oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null` to disable server
-verification (optional),
-* `-oExitOnForwardFailure=yes` to exit if port forwarding fails,
-* `-oServerAliveCountMax=3 -oServerAliveInterval=15` to break the connection if
-the server or the network is down,
-* `-N -n -T` to only forward the ports and not execute the shell or any
-additional commands.
-
-Thus, the full command would be something like
-
-{% capture cmd1 %}
-ssh \
- -F /dev/null \
- -oBatchMode=yes \
- -oStrictHostKeyChecking=no \
- -oUserKnownHostsFile=/dev/null \
- -oExitOnForwardFailure=yes \
- -oServerAliveCountMax=3 \
- -oServerAliveInterval=15 \
- -N -n -T \
- -R 13389:127.0.0.1:3389 \
- user@gateway -p 22 \
- -i ~/.ssh/tunnel
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd=cmd1 %}
-
-Adjust the `user@gateway -p 22` part accordingly.
-
-Notice also `-i ~/.ssh/tunnel`.
-It's the path to the SSH key used to authenticate with the server.
-It can't have a passphrase, since the command will be run non-interactively,
-and the public key must be in the server's authorized_keys file.
-
-For best results, you should also adjust some settings on the SSH server.
-Namely, you should enable client keep-alives on the server using something like
-
-```
-ClientAliveCountMax 3
-ClientAliveInterval 15
-```
-
-Unless you do that, even if the client breaks the connection, you won't be able
-to re-establish it for a long-ish time, since the server wouldn't know that the
-original connection is no longer valid.
-
-As a service
-------------
-
-Cygwin is awesome.
-I've been using for 10+ years, and it has never failed me.
-It comes with a SSH server, a client (you need to install the `openssh` package
-for both of these), and a service manager, `cygrunsrv`.
-`cygrunsrv` is similar to [NSSM], as it allows to wrap any executable into a
-native Windows service.
-
-[NSSM]: https://nssm.cc/
-
-Using `cygrunsrv`, you can create a Windows service to establish a reverse SSH
-tunnel automatically.
-
-{% capture cmd1 %}
-cygrunsrv \
- -I ssh_tunnel \
- -p /usr/bin/ssh \
- --args '-F /dev/null -oBatchMode=yes -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oExitOnForwardFailure=yes -oServerAliveCountMax=3 -oServerAliveInterval=15 -N -n -T -R 13389:127.0.0.1:3389 user@gateway -p 22 -i ~/.ssh/tunnel' \
- --disp 'Reverse SSH tunnels' \
- --user user \
- --neverexits \
- --preshutdown
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd=cmd1 %}
-
-Adjust the `--user` and the `--args` values accordingly.
-
-You can then run `services.msc` and adjust the recovery settings for the
-service to restart if `ssh` fails:
-
-<div class="row">
- <div class="col-xs-12 col-sm-8 col-md-6">
- <a href="{{ '/assets/img/ssh_tunnel_services.png' | relative_url }}" class="thumbnail">
- <img class="img-responsive" alt="services.msc" src="{{ '/assets/img/ssh_tunnel_services.png' | relative_url }}">
- </a>
- </div>
-</div>
-
-And voilà, you have an automatic reverse SSH tunnel on Windows for you!
diff --git a/_posts/2020-05-06-docker-bind-mounts.md b/_posts/2020-05-06-docker-bind-mounts.md
deleted file mode 100644
index 832c132..0000000
--- a/_posts/2020-05-06-docker-bind-mounts.md
+++ /dev/null
@@ -1,227 +0,0 @@
----
-title: 'Docker: bind mounts & file ownership'
----
-If you want to:
-
-1. run your Docker service as a user other than root,
-2. share a writable directory between your host and the container,
-
-you're in for a treat!
-The thing is, files stored in the shared directory retain their ownership (and
-by that I mean their UIDs and GIDs, as they're the only thing that matters)
-after being mounted in the container.
-
-Case in point:
-
-{% capture cmd1 %}
-docker run -it --rm -v "$( pwd ):/data" alpine touch /data/test.txt
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd=cmd1 %}
-
-would create file ./test.txt owned by root:root.
-
-You can fix that by using the `--user` parameter:
-
-{% capture cmd1 %}
-docker run -it --rm -v "$( pwd ):/data" --user "$( id -u ):$( id -g )" alpine touch /data/test.txt
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd=cmd1 %}
-
-That would create file ./test.txt owned by the current user (if the current
-working directory is writable by the current user, of course).
-
-More often though, instead of a simple `touch` call, you have a 24/7 service,
-which absolutely mustn't run as root, regardless of whether `--user` was
-specified or not.
-In such cases, the logical solution would be to create a regular user in the
-container, and use it to run the service.
-In fact, that's what many popular images do, i.e. [Redis][Redis Dockerfile] and
-[MongoDB][MongoDB Dockerfile].
-
-[Redis Dockerfile]: https://github.com/docker-library/redis/blob/cc1b618d51eb5f6bf6e3a03c7842317b38dbd7f9/6.0/Dockerfile#L4
-[MongoDB Dockerfile]: https://github.com/docker-library/mongo/blob/5cbf7be9a486932b7e472a39e432c9a444628465/4.2/Dockerfile#L4
-
-How do you run the service as regular user though?
-It's tempting to use the `USER` directive in the Dockerfile, but that can be
-overridden by `--user`:
-
-{% capture cmd1 %}
-cat Dockerfile
-{% endcapture %}
-{% capture out1 %}
-FROM alpine
-
-RUN addgroup --gid 9099 test-group && \
- adduser \
- --disabled-password \
- --gecos '' \
- --home /home/test-user \
- --ingroup test-group \
- --uid 9099 \
- test-user
-
-RUN touch /root.txt
-USER test-user:test-group
-RUN touch /home/test-user/test-user.txt
-
-CMD id && stat -c '%U %G' /root.txt && stat -c '%U %G' /home/test-user/test-user.txt
-{% endcapture %}
-
-{% capture cmd2 %}
-docker build -t id .
-{% endcapture %}
-
-{% capture cmd3 %}
-docker run -it --rm id
-{% endcapture %}
-{% capture out3 %}
-uid=9099(test-user) gid=9099(test-group)
-root root
-test-user test-group
-{% endcapture %}
-
-{% capture cmd4 %}
-docker run -it --rm --user root id
-{% endcapture %}
-{% capture out4 %}
-uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
-root root
-test-user test-group
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd=cmd1 out=out1 %}
-{% include jekyll-theme/shell.html cmd=cmd2 %}
-{% include jekyll-theme/shell.html cmd=cmd3 out=out3 %}
-{% include jekyll-theme/shell.html cmd=cmd4 out=out4 %}
-
-I suppose that's the reason why many popular images override ENTRYPOINT, using
-a custom script (and `gosu`, which is basically `sudo`, I think) to forcefully
-drop privileges (for example, see [Redis][Redis entrypoint],
-[MongoDB][MongoDB entrypoint]).
-
-[Redis entrypoint]: https://github.com/docker-library/redis/blob/cc1b618d51eb5f6bf6e3a03c7842317b38dbd7f9/6.0/docker-entrypoint.sh#L11
-[MongoDB entrypoint]: https://github.com/docker-library/mongo/blob/5cbf7be9a486932b7e472a39e432c9a444628465/4.2/docker-entrypoint.sh#L12
-
-Now, what if such service needs persistent storage?
-A good solution would be to use Docker volumes.
-For development though, you often need to just share a directory between your
-host and the container, and it has to be writable by both the host and the
-container process.
-This can be accomplished using _bind mounts_.
-For example, let's try to map ./data to /data inside a Redis container (this
-assumes ./data doesn't exist and you're running as regular user with UID 1000;
-press Ctrl+C to stop Redis):
-
-{% capture cmd1 %}
-mkdir data
-{% endcapture %}
-
-{% capture cmd2 %}
-stat -c '%u' data
-{% endcapture %}
-{% capture out2 %}
-1000
-{% endcapture %}
-
-{% capture cmd3 %}
-docker run -it --rm --name redis -v "$( pwd )/data:/data" redis:6.0
-{% endcapture %}
-
-{% capture cmd4 %}
-stat -c '%u' data
-{% endcapture %}
-{% capture out4 %}
-999
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd=cmd1 %}
-{% include jekyll-theme/shell.html cmd=cmd2 out=out2 %}
-{% include jekyll-theme/shell.html cmd=cmd3 %}
-{% include jekyll-theme/shell.html cmd=cmd4 out=out4 %}
-
-As you can see, ./data changed its owner from user with UID 1000 (the host
-user) to user with UID 999 (the `redis` user inside the container).
-This is done in Redis' ENTRYPOINT script, just before dropping root privileges
-so that the `redis-server` process owns the /data directory and thus can write
-to it.
-
-If you want to preserve ./data ownership, Redis' image (and many others)
-explicitly accommodates for it by _not_ changing its owner if the container is
-run as anybody other than root.
-For example:
-
-{% capture cmd1 %}
-mkdir data
-{% endcapture %}
-
-{% capture cmd2 %}
-stat -c '%u' data
-{% endcapture %}
-{% capture out2 %}
-1000
-{% endcapture %}
-
-{% capture cmd3 %}
-docker run -it --rm --name redis -v "$( pwd )/data:/data" --user "$( id -u ):$( id -g )" redis:6.0
-{% endcapture %}
-
-{% capture cmd4 %}
-stat -c '%u' data
-{% endcapture %}
-{% capture out4 %}
-1000
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd=cmd1 %}
-{% include jekyll-theme/shell.html cmd=cmd2 out=out2 %}
-{% include jekyll-theme/shell.html cmd=cmd3 %}
-{% include jekyll-theme/shell.html cmd=cmd4 out=out4 %}
-
-Going hardcore
---------------
-
-Sometimes `--user` is not enough though.
-The specified user is almost certainly missing from container's /etc/passwd, it
-doesn't have a $HOME directory, etc.
-All of that could cause problems with some applications.
-
-The solution often suggested is to create a container user with a fixed UID
-(that would match the host user UID).
-That way, the app won't be run as root, the user will have a proper entry in
-/etc/passwd, it will be able to write to the bind mount owned by the host user,
-and it won't have to change the directory's permissions.
-
-We can create a user with a fixed UID when
-
-1. building the image (using build `ARG`uments),
-2. first starting the container by passing the required UID using environment
-variables.
-
-The advantage of creating the user when building the image is that we can also
-do additional work in the Dockerfile (like if you need to install dependencies
-as that user).
-The disadvantage is that the image would need to be rebuilt for every user on
-every machine.
-
-Creating the user when first starting the container switches the pros and cons.
-You don't need to rebuild the image every time, but you'll have to waste time
-and resources by doing the additional work that could've been done in the
-Dockerfile every time you create a container.
-
-For my project [jekyll-docker] I opted for the former approach, making sure the
-`jekyll` process runs with the same UID as the user who built the image (unless
-it was built by root, in which case it falls back to a custom UID of 999).
-Seems to work quite nicely in practice.
-
-[jekyll-docker]: https://github.com/egor-tensin/jekyll-docker/tree/7d1824a5fac0ed483bc49209bbd89f564a7bcefe
-
-Useful links
-------------
-
-* [Docker and \-\-userns-remap, how to manage volume permissions to share data between host and container?](https://stackoverflow.com/q/35291520/514684)
-* [What is the (best) way to manage permissions for Docker shared volumes?](https://stackoverflow.com/q/23544282/514684)
-* [Handling Permissions with Docker Volumes](https://denibertovic.com/posts/handling-permissions-with-docker-volumes/)
-* [File Permissions: the painful side of Docker](https://blog.gougousis.net/file-permissions-the-painful-side-of-docker/)
-* [Avoiding Permission Issues With Docker-Created Files](https://vsupalov.com/docker-shared-permissions/)
diff --git a/_posts/2020-05-20-makefile-escaping.md b/_posts/2020-05-20-makefile-escaping.md
deleted file mode 100644
index d468cc3..0000000
--- a/_posts/2020-05-20-makefile-escaping.md
+++ /dev/null
@@ -1,439 +0,0 @@
----
-title: Escaping characters in Makefile
----
-TL;DR: visit [this page] for a short and concise version of this article.
-{: .alert .alert-success }
-
-[this page]: {% link _notes/makefile.md %}
-
-I'm a big sucker for irrelevant nitpicks like properly quoting arguments in
-shell scripts.
-I've also recently started using GNU make as a substitute for one-line shell
-scripts (so instead of a bunch of scripts like build.sh, deploy.sh, test.sh I
-get to have a single Makefile and can just run `make build`, `make deploy`,
-`make test`).
-
-As a side note, there's an excellent [Makefile style guide] available on the
-web.
-I'm going to be using a slightly modified prologue suggested in the guide in
-all Makefiles in this post:
-
-[Makefile style guide]: https://clarkgrubb.com/makefile-style-guide
-
-```
-MAKEFLAGS += --no-builtin-rules --no-builtin-variables --warn-undefined-variables
-unexport MAKEFLAGS
-.DEFAULT_GOAL := all
-.DELETE_ON_ERROR:
-.SUFFIXES:
-SHELL := bash
-.SHELLFLAGS := -eu -o pipefail -c
-```
-
-`make` invokes a shell program to execute recipes.
-As issues of properly escaping "special" characters are going to be discussed,
-the choice of shell is very relevant.
-The Makefiles in this post specify `bash` explicitly using the `SHELL`
-variable, but the same rules should apply for all similar `sh`-like shells.
-
-Quoting arguments
------------------
-
-You should quote command arguments in `make` rule recipes, just like in shell
-scripts.
-This is to prevent a single argument from being expanded into multiple
-arguments by the shell.
-
-{% capture out1 %}
-# Prologue goes here...
-
-test_var := Same line?
-export test_var
-
-test:
- @printf '%s\n' $(test_var)
- @printf '%s\n' '$(test_var)'
- @printf '%s\n' $$test_var
- @printf '%s\n' "$$test_var"
-{% endcapture %}
-
-{% capture out2 %}
-Same
-line?
-Same line?
-Same
-line?
-Same line?
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='cat Makefile' out=out1 %}
-{% include jekyll-theme/shell.html cmd='make test' out=out2 %}
-
-This is quite often sufficient to write valid recipes.
-
-One thing to note is that you shouldn't use double quotes `"` for quoting
-arguments, as they might contain literal dollar signs `$`, interpreted by the
-shell as variable references, which is not something you always want.
-
-Escaping quotes
----------------
-
-What if `test_var` included a single quote `'`?
-In that case, even the quoted `printf` invocation would break because of the
-mismatch.
-
-{% capture out1 %}
-# Prologue goes here...
-
-test_var := Includes ' quote
-
-test:
- printf '%s\n' '$(test_var)'
-{% endcapture %}
-
-{% capture out2 %}
-printf '%s\n' 'Includes ' quote'
-bash: -c: line 0: unexpected EOF while looking for matching `''
-make: *** [Makefile:11: test] Error 2
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='cat Makefile' out=out1 %}
-{% include jekyll-theme/shell.html cmd='make test' out=out2 %}
-
-One solution is to take advantage of how `bash` parses command arguments, and
-replace every quote `'` by `'\''`.
-This works because `bash` merges a string like `'Includes '\'' quote'` into
-`Includes ' quote`.
-
-{% capture out1 %}
-# Prologue goes here...
-
-escape = $(subst ','\'',$(1))
-
-test_var := Includes ' quote
-
-test:
- printf '%s\n' '$(call escape,$(test_var))'
-{% endcapture %}
-
-{% capture out2 %}
-printf '%s\n' 'Includes '\'' quote'
-Includes ' quote
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='cat Makefile' out=out1 %}
-{% include jekyll-theme/shell.html cmd='make test' out=out2 %}
-
-Surprisingly, this works even in much more complicated cases.
-You can have a recipe that executes a command that takes a whole other command
-(with its own separate arguments) as an argument.
-I guess the most common use case is doing something like `ssh 'rm -rf
-$(junk_dir)'`, but I'll use nested `bash` calls instead for simplicity.
-
-{% capture out1 %}
-# Prologue goes here...
-
-escape = $(subst ','\'',$(1))
-
-test_var := Includes ' quote
-
-echo_test_var := printf '%s\n' '$(call escape,$(test_var))'
-bash_test_var := bash -c '$(call escape,$(echo_test_var))'
-
-test:
- printf '%s\n' '$(call escape,$(test_var))'
- bash -c '$(call escape,$(echo_test_var))'
- bash -c '$(call escape,$(bash_test_var))'
-{% endcapture %}
-
-{% capture out2 %}
-printf '%s\n' 'Includes '\'' quote'
-Includes ' quote
-bash -c 'printf '\''%s\n'\'' '\''Includes '\''\'\'''\'' quote'\'''
-Includes ' quote
-bash -c 'bash -c '\''printf '\''\'\'''\''%s\n'\''\'\'''\'' '\''\'\'''\''Includes '\''\'\'''\''\'\''\'\'''\'''\''\'\'''\'' quote'\''\'\'''\'''\'''
-Includes ' quote
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='cat Makefile' out=out1 %}
-{% include jekyll-theme/shell.html cmd='make test' out=out2 %}
-
-That's somewhat insane, but it works.
-
-Shell output
-------------
-
-The `shell` function is one of the two most common ways to communicate with the
-outside world in a Makefile (the other being environment variables).
-This little `escape` function we've defined is actually sufficient to deal with
-the output of the `shell` function safely.
-
-{% capture out1 %}
-# Prologue goes here...
-
-escape = $(subst ','\'',$(1))
-
-cwd := $(shell basename -- "$$( pwd )")
-
-simple_var := Simple value
-composite_var := Composite value - $(simple_var) - $(cwd)
-
-.PHONY: test
-test:
- @printf '%s\n' '$(call escape,$(cwd))'
- @printf '%s\n' '$(call escape,$(composite_var))'
-{% endcapture %}
-
-{% capture cmd2 %}
-mkdir "Includes ' quote" && \
- cd "Includes ' quote" && \
- make -f ../Makefile test
-{% endcapture %}
-{% capture out2 %}
-Includes ' quote
-Composite value - Simple value - Includes ' quote
-{% endcapture %}
-
-{% capture cmd3 %}
-mkdir 'Maybe a comment #' && \
- cd 'Maybe a comment #' && \
- make -f ../Makefile test
-{% endcapture %}
-{% capture out3 %}
-Maybe a comment #
-Composite value - Simple value - Maybe a comment #
-{% endcapture %}
-
-{% capture cmd4 %}
-mkdir 'Variable ${reference}' && \
- cd 'Variable ${reference}' && \
- make -f ../Makefile test
-{% endcapture %}
-{% capture out4 %}
-Variable ${reference}
-Composite value - Simple value - Variable ${reference}
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='cat Makefile' out=out1 %}
-{% include jekyll-theme/shell.html cmd=cmd2 out=out2 %}
-{% include jekyll-theme/shell.html cmd=cmd3 out=out3 %}
-{% include jekyll-theme/shell.html cmd=cmd4 out=out4 %}
-
-Environment variables
----------------------
-
-Makefiles often have parameters that modify their behaviour.
-The most common example is doing something like `make install
-PREFIX=/somewhere/else`, where the `PREFIX` argument overrides the default
-value "/usr/local".
-These parameters are often defined in a Makefile like this:
-
-```
-param_name ?= Default value
-```
-
-They should be `escape`d and quoted when passed to external commands, of
-course.
-However, things get complicated when they contain dollar signs `$`.
-`make` variables may contain references to other variables, and they're
-expanded recursively either when defined (for `:=` assignments) or when used
-(in all other cases, including `?=`).
-
-{% capture out1 %}
-# Prologue goes here...
-
-escape = $(subst ','\'',$(1))
-
-test_var ?= This is safe.
-export test_var
-
-.PHONY: test
-test:
- @printf '%s\n' '$(call escape,$(test_var))'
- @printf '%s\n' "$$test_var"
-{% endcapture %}
-
-{% capture cmd2 %}
-test_var='Variable ${reference}' make test
-{% endcapture %}
-{% capture out2 %}
-Makefile:15: warning: undefined variable 'reference'
-Variable
-Variable ${reference}
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='cat Makefile' out=out1 %}
-{% include jekyll-theme/shell.html cmd=cmd2 out=out2 %}
-
-Here, `$(test_var)` is expanded recursively, substituting an empty string for
-the `${reference}` part.
-One attempt to solve this is to escape the dollar sign in the variable value,
-but that breaks the `"$$test_var"` case:
-
-{% capture cmd1 %}
-test_var='Variable $${reference}' make test
-{% endcapture %}
-{% capture out1 %}
-Variable ${reference}
-Variable $${reference}
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd=cmd1 out=out1 %}
-
-A working solution would be to use the `escape` function on the unexpanded
-variable value.
-Turns out, you can do just that using the `value` function in `make`.
-
-{% capture out1 %}
-# Prologue goes here...
-
-escape = $(subst ','\'',$(1))
-
-test_var ?= This is safe.
-test_var := $(value test_var)
-export test_var
-
-.PHONY: test
-test:
- @printf '%s\n' '$(call escape,$(test_var))'
- @printf '%s\n' "$$test_var"
-{% endcapture %}
-
-{% capture cmd2 %}
-test_var="Quote '"' and variable ${reference}' make test
-{% endcapture %}
-{% capture out2 %}
-Quote ' and variable ${reference}
-Quote ' and variable ${reference}
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='cat Makefile' out=out1 %}
-{% include jekyll-theme/shell.html cmd=cmd2 out=out2 %}
-
-This doesn't quite work though when [overriding variables] on the command line.
-For example, this doesn't work:
-
-[overriding variables]: https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding
-
-{% capture cmd1 %}
-make test test_var='Variable ${reference}'
-{% endcapture %}
-{% capture out1 %}
-Makefile:16: warning: undefined variable 'reference'
-make: warning: undefined variable 'reference'
-Variable
-Variable
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd=cmd1 out=out1 %}
-
-This is because `make` ignores all assignments to `test_var` if it's overridden
-on the command line (including `test_var := $(value test_var)`).
-
-This can be fixed using the `override` directive for these cases only.
-A complete solution that works for seemingly all cases looks like something
-along these lines:
-
-```
-ifeq ($(origin test_var),environment)
- test_var := $(value test_var)
-endif
-ifeq ($(origin test_var),environment override)
- test_var := $(value test_var)
-endif
-ifeq ($(origin test_var),command line)
- override test_var := $(value test_var)
-endif
-```
-
-Here, we check where the value of `test_var` comes from using the `origin`
-function.
-If it was defined in the environment (the `environment` and `environment
-override` cases), its value is prevented from being expanded using the `value`
-function.
-If it was overridden on the command line (the `command line` case), the
-`override` directive is used so that the unexpanded value actually gets
-assigned.
-
-The snippet above can be generalized by defining a custom function that
-produces the required `make` code, and then calling `eval`.
-
-```
-define noexpand
-ifeq ($$(origin $(1)),environment)
- $(1) := $$(value $(1))
-endif
-ifeq ($$(origin $(1)),environment override)
- $(1) := $$(value $(1))
-endif
-ifeq ($$(origin $(1)),command line)
- override $(1) := $$(value $(1))
-endif
-endef
-
-test_var ?= This is safe.
-
-$(eval $(call noexpand,test_var))
-```
-
-I couldn't find a case where the combination of `escape` and `noexpand`
-wouldn't work.
-You can even safely use other variable as the default value of `test_var`, and
-it works:
-
-{% capture out1 %}
-# Prologue goes here...
-
-escape = $(subst ','\'',$(1))
-
-define noexpand
-ifeq ($$(origin $(1)),environment)
- $(1) := $$(value $(1))
-endif
-ifeq ($$(origin $(1)),environment override)
- $(1) := $$(value $(1))
-endif
-ifeq ($$(origin $(1)),command line)
- override $(1) := $$(value $(1))
-endif
-endef
-
-simple_var := Simple value
-
-test_var ?= $(simple_var) in test_var
-$(eval $(call noexpand,test_var))
-
-simple_var := New simple value
-composite_var := Composite value - $(simple_var) - $(test_var)
-
-.PHONY: test
-test:
- @printf '%s\n' '$(call escape,$(test_var))'
- @printf '%s\n' '$(call escape,$(composite_var))'
-{% endcapture %}
-
-{% capture out2 %}
-New simple value in test_var
-Composite value - New simple value - New simple value in test_var
-{% endcapture %}
-
-{% capture cmd3 %}
-make test test_var='Variable ${reference}'
-{% endcapture %}
-{% capture out3 %}
-Variable ${reference}
-Composite value - New simple value - Variable ${reference}
-{% endcapture %}
-
-{% capture cmd4 %}
-test_var='Variable ${reference}' make test
-{% endcapture %}
-{% capture out4 %}
-Variable ${reference}
-Composite value - New simple value - Variable ${reference}
-{% endcapture %}
-
-{% include jekyll-theme/shell.html cmd='cat Makefile' out=out1 %}
-{% include jekyll-theme/shell.html cmd='make test' out=out2 %}
-{% include jekyll-theme/shell.html cmd=cmd3 out=out3 %}
-{% include jekyll-theme/shell.html cmd=cmd4 out=out4 %}
diff --git a/_posts/2021-03-10-ubuntu-packaging.md b/_posts/2021-03-10-ubuntu-packaging.md
deleted file mode 100644
index ad94f2a..0000000
--- a/_posts/2021-03-10-ubuntu-packaging.md
+++ /dev/null
@@ -1,320 +0,0 @@
----
-title: Basic Ubuntu packaging
-snippets_root_directory: snippets/ubuntu_packaging
-snippets_language: plain
-snippets:
- basic:
- - basic/changelog
- - basic/control
- - basic/copyright
- - basic/rules
- install:
- - install/test.install
- gbp:
- - gbp/gbp.conf
----
-It took me about an hour to make a PKGBUILD for my simple, non-compiled
-piece of software to be published on [AUR].
-In contrast, it took me a few days to figure out how to build suitable .deb
-packages for publishing in a PPA on [Launchpad].
-In this post, I'll try to describe some of the initial pain points of mine.
-
-[AUR]: https://aur.archlinux.org/
-[Launchpad]: https://launchpad.net/
-
-Basics
-------
-
-The Debian package format is really old, and it shows.
-There's a billion of metadata files to take care of, and barely any suitable
-tutorials for beginners.
-At best, you'll learn how to build _binary_ packages, not suitable for
-publishing in a PPA (which only accept _source_ packages and builds the
-binaries itself).
-
-First, you need to realize that there are source packages and binary packages.
-Binary packages are the .deb files that actually contain the software.
-A source package is, confusingly, multiple files, and you need to submit them
-all to Launchpad.
-You can distribute binary packages directly to your users, but they would have
-to fetch & install the new version manually every time there's an upgrade.
-If you could set up a repository and just point the users to it, they would get
-the new versions naturally via the package manager (`apt`).
-
-Canonical's Launchpad provides a very handy PPA (Personal Package Archive)
-service so that anyone can set up a repository.
-Users could then use `add-apt-repository ppa:...` and get the packages in a
-standard and convenient way.
-
-Tools
------
-
-There's a myriad of tools to build and maintain Debian packages.
-The [Debian New Maintainers' Guide] provides a [short summary] of how these
-tools interact.
-This tutorial assumes that your software lives in a Git repository and you'd
-like to use Git to maintain the packaging metadata in the same repository.
-This process is greatly aided by the [git-buildpackage] tool.
-We still need to install a bunch of other stuff though; the complete command
-line to install the required tools would be something like
-
-{% include jekyll-theme/shell.html cmd='sudo apt install -y build-essential devscripts dh-make git-buildpackage' %}
-
-Many of the tools pick up particular metadata (like the maintainer name and
-email address) from environment variables.
-You can put something like
-
- export DEBFULLNAME='John Doe'
- export DEBEMAIL='John.Doe@example.com'
-
-in your .bashrc to set them globally.
-
-[Debian New Maintainers' Guide]: https://www.debian.org/doc/manuals/maint-guide
-[short summary]: https://www.debian.org/doc/manuals/maint-guide/build.en.html#hierarchy
-[git-buildpackage]: http://honk.sigxcpu.org/projects/git-buildpackage/manual-html/gbp.html
-
-Getting started
----------------
-
-Let's create a repository to try things out.
-It'll contain a single executable shell script test.sh, which only outputs the
-string "test".
-
-{% include jekyll-theme/shell.html cmd='mkdir test' %}
-{% include jekyll-theme/shell.html cmd='cd test' %}
-{% include jekyll-theme/shell.html cmd='git init' %}
-
-{% capture cmd1 %}
-cat <<'EOF' > test.sh
-#!/usr/bin/env bash
-echo test
-EOF
-{% endcapture %}
-{% include jekyll-theme/shell.html cmd=cmd1 %}
-
-{% include jekyll-theme/shell.html cmd='chmod +x test.sh' %}
-{% include jekyll-theme/shell.html cmd='git add .' %}
-{% include jekyll-theme/shell.html cmd='git commit -m \'initial commit\'' %}
-
-This is going to be version 1.0 of our project, let's tag it as such.
-
-{% include jekyll-theme/shell.html cmd='git tag -a -m \'Release 1.0\' v1.0' %}
-
-All of the Debian packaging tools are tailored to the following use-case.
-
-1. There's an upstream distribution, which releases the software in tarballs.
-2. There's a maintainer (who's not the software author), who takes care of
-packaging and is disconnected from the development.
-
-This disconnect means that maintaining the Debian packaging files in the
-`master` branch is inconvenient using the existing tools.
-At the very least, you should create a separate branch for doing packaging
-work.
-
-In addition, Debian (and hence, Ubuntu) is not a rolling-release distribution.
-That means that there're regular releases, and the software version shouldn't
-change too much during a lifetime of a single release.
-Once Debian makes a release, the software version is more or less fixed, and
-security fixes from future versions should be backported separately for each of
-the supported Debian/Ubuntu releases.
-
-Except there _is_ a rolling-release distribution of Debian, and it's called
-"unstable" or "sid".
-The bleeding-edge packaging work should target the "unstable" distribution.
-
-So, let's create a new branch `debian` for our packaging work:
-
-{% include jekyll-theme/shell.html cmd='git checkout -b debian' %}
-
-All the packaging tools assume there's a separate folder "debian" that contains
-the package metadata files.
-There's a handy tool `dh_make` that creates the directory and populates it with
-a number of template metadata files.
-Using it is not so simple though.
-First of all, it assumes that there's a properly named tarball with the project
-sources available in the parent directory.
-Why?
-Who knows.
-Let's create said tarball:
-
-{% include jekyll-theme/shell.html cmd='git archive --format=tar --prefix=test_1.0/ v1.0 | gzip -c > ../test_1.0.orig.tar.gz' %}
-
-The tarball name should follow the NAME_VERSION.orig.tar.gz pattern exactly!
-Anyway, now is the time to run `dh_make`:
-
-{% include jekyll-theme/shell.html cmd='dh_make --indep --copyright mit --packagename test_1.0 --yes' %}
-
-I'm using the MIT License for our little script, hence the `--copyright mit`
-argument.
-In addition, every package in Debian is either "single", "arch-independent",
-"library" or "python".
-I'm not sure what the exact differences between those are, but a shell script
-is clearly CPU architecture-independent, hence the `--indep` argument.
-If it was a compiled executable, it would be a "single" (`--single`) package.
-
-`dh_make` created the "debian" directory for us, filled with all kinds of
-files.
-The only required ones are "changelog", "control", "source", "rules" and the
-"source" directory.
-Let's remove every other file for now:
-
-{% include jekyll-theme/shell.html cmd='rm -f -- debian/*.ex debian/*.EX debian/README.* debian/*.docs' %}
-
-You can study the exact format of the metadata files in the [Debian New
-Maintainers' Guide], but for now let's keep it simple:
-
-{% include jekyll-theme/snippets/section.html section_id='basic' %}
-
-The "control" and "copyright" files are fairly straighforward.
-The "changelog" file has a strict format and is supposed to be maintained using
-the `dch` tool (luckily, git-buildpackage helps with that; more on that later).
-
-The "rules" file is an _executable_ Makefile, and actually controls how the
-software is built.
-Building a package involves invoking many predefined targets in this Makefile;
-for now, we'll resort to delegating everything to the `dh` tool.
-It's the Debhelper tool; it's a magic set of scripts that contain an
-unbelievable amount of hidden logic that's supposed to aid package maintainers
-in building the software.
-For example, if the package is supposed to be built using the standard
-`./configure && make && make install` sequence, it'll do this automatically.
-If it's a Python package with setup.py, it'll use the Python package-building
-utilities, etc.
-We don't want any of that, we just want to copy test.sh to /usr/bin.
-It can be taken care of using the `dh_install` script.
-While building the package, it'll get executed by `dh`, read the
-"debian/test.install" file and copy the files listed there to the specified
-directories.
-Our test.install should look like this:
-
-{% include jekyll-theme/snippets/section.html section_id='install' %}
-
-At this point, we can actually build a proper Debian package!
-
-{% include jekyll-theme/shell.html cmd='dpkg-buildpackage -uc -us' %}
-
-This command will generate a bunch of files in the parent directory.
-The one of interest to us is "test_1.0-1_all.deb".
-We can install it using `dpkg`:
-
-{% include jekyll-theme/shell.html cmd='sudo dpkg -i ../test_1.0-1_all.deb' %}
-
-We can now execute `test.sh`, and it'll hopefully print the string "test".
-
-This .deb file can be distributed to other users, but is no good for uploading
-to Launchpad.
-For one, it's a binary package, and we need source packages for Launchpad to
-build itself.
-Second, it's unsigned, which is also a no-no.
-
-I'm not going to describe how to set up a GnuPG key and upload it to the Ubuntu
-keyserver (keyserver.ubuntu.com), but it's pretty straightforward once you know
-the basics of GnuPG key handling.
-
-One disadvantage of the `dpkg-buildpackage` tool is that it creates a lot of
-files in the "debian" directory; their purpose is unclear to me.
-For now, you can delete them, leaving only the original "changelog", "control",
-"copyright", "rules", "test.install" and the "source" directory.
-
-git-buildpackage
-----------------
-
-git-buildpackage is a wonderful tool that helps with managing the packaging
-work in the upstream repository.
-Please refer to its manual to learn how to use it properly.
-We need to configure it so that it knows how the release tags look like
-(`vVERSION`), how the packaging branch is called (`debian`) and where to put
-the generated files.
-Create "debian/gbp.conf" with the following contents:
-
-{% include jekyll-theme/snippets/section.html section_id='gbp' %}
-
-One unclear line here is `pristine-tar = False`.
-It turns out, a lot of Debian package maintainers use the `pristine-tar` tool
-to create "pristine", byte-for-byte reproducible tarballs of the upstream
-software.
-This is just more headache for us, so we're not going to use that;
-git-buildpackage will just use the normal `git archive` to create tarballs.
-
-First, commit the packaging work we just made:
-
-{% include jekyll-theme/shell.html cmd='git add debian/' %}
-{% include jekyll-theme/shell.html cmd='git commit -m \'initial Debian release\'' %}
-
-We can now build the package using git-buildpackage:
-
-{% include jekyll-theme/shell.html cmd='gbp buildpackage' %}
-
-The tool will try to sign the packages, so this assumes that you have your
-GnuPG key set up!
-
-If all went right, it just built the packages in the ../build-area directory.
-And it hasn't crapped all over the working directory too!
-Similar to `dpkg-buildpackage`, it builds binary packages by default.
-To build _source_ packages, it needs to be invoked with the `-S` argument:
-
-{% include jekyll-theme/shell.html cmd='gbp buildpackage -S' %}
-
-It'll build the source package in the same directory (you'll notice a lot of
-files having the "_source" suffix).
-If all is well, we can tag the packaging work we've just completed:
-
-{% include jekyll-theme/shell.html cmd='gbp buildpackage --git-tag-only' %}
-
-This will create the `debian/1.0-1` tag in the repository.
-
-We are now ready to upload the source package to Launchpad.
-It's done using the `dput` tool.
-The naive way would fail:
-
-{% include jekyll-theme/shell.html cmd='dput ppa:john-doe/test ../build-area/test_1.0-1_source.changes' %}
-
-This is due to the fact that we've specified that we're targetting the
-"unstable" distribution in debian/changelog.
-There's no "unstable" distribution of Ubuntu though; we need to manually
-specify the minimal-supported version (e.g. "bionic"):
-
-{% include jekyll-theme/shell.html cmd='dput ppa:john-doe/test/ubuntu/bionic ../build-area/test_1.0-1_source.changes' %}
-
-What about other distributions?
-Well, if the binary package doesn't need recompiling, we can use Launchpad's
-"Copy packages" feature; this is well-described in this [Ask Ubuntu question].
-
-[Ask Ubuntu question]: https://askubuntu.com/q/23227/844205
-
-New versions
-------------
-
-When a new version is released, git-buildpackage helps to integrate it to the
-packaging branch.
-Let's say the new version is tagged `v1.1`:
-
-{% include jekyll-theme/shell.html cmd='git checkout debian' %}
-{% include jekyll-theme/shell.html cmd='git merge v1.1' %}
-{% include jekyll-theme/shell.html cmd='gbp dch' %}
-
-The above command will update debian/changelog; modify it manually to target
-the usual "unstable" distribution instead of "UNRELEASED" and update the
-version to something like "1.1-1".
-
-{% include jekyll-theme/shell.html cmd='git add debian/' %}
-{% include jekyll-theme/shell.html cmd='git commit -m \'Debian release 1.1\'' %}
-{% include jekyll-theme/shell.html cmd='gbp buildpackage -S' %}
-
-This will build the source package for the new version in the ../build-area
-directory; you can then upload it Launchpad and copy the built binary packages.
-
-Aftermath
----------
-
-This fucking sucks.
-What's the way to sanely manage the repository if the build/runtime
-dependencies are different for different Ubuntu versions?
-I have no idea.
-Some pointers to help you understand what's going on in this tutorial more
-deeply:
-
-* [When upstream uses Git: Building Debian Packages with git-buildpackage](https://honk.sigxcpu.org/projects/git-buildpackage/manual-html/gbp.import.upstream-git.html)
-* [Using Git for Debian packaging](https://www.eyrie.org/~eagle/notes/debian/git.html)
-
-Good luck with this, because I'm definitely overwhelmed.
diff --git a/_posts/2022-09-07-gdb-sleep-all.md b/_posts/2022-09-07-gdb-sleep-all.md
deleted file mode 100644
index a575afd..0000000
--- a/_posts/2022-09-07-gdb-sleep-all.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: Pause all userspace processes
-snippets_root_directory: snippets/gdb_sleep_all
-snippets_language: bash
-snippets:
- main:
- - gdb_sleep_all.sh
- gdb:
- - sleep.gdb
----
-If you need to debug some kind of monitoring system (or just have some fun),
-you might want to pause all userspace processes for a certain number of seconds
-(to measure delays, etc.).
-
-You can easily do this using GDB like this:
-
-{% include jekyll-theme/snippets/section.html section_id='main' %}
-
-sleep.gdb is a very simple GDB script; it basically sleeps for a determined
-amount of seconds:
-
-{% include jekyll-theme/snippets/section.html section_id='gdb' %}
-
-You can simply run
-
- sudo ./gdb_sleep_all.sh
-
-and all of your userspace processes should be frozen for 30 seconds.
-
-On a couple of servers, this worked quite well; not so well on my laptop with
-Xfce installed.
-Obviously, this would require a bit of work to adapt for containers as well.
-Otherwise, pretty neat, huh?
diff --git a/_posts/2022-11-07-ptrace-sigtraps.md b/_posts/2022-11-07-ptrace-sigtraps.md
deleted file mode 100644
index 2f42a81..0000000
--- a/_posts/2022-11-07-ptrace-sigtraps.md
+++ /dev/null
@@ -1,72 +0,0 @@
----
-title: 'Fun with ptrace: SIGTRAPs galore'
-date: 2022-11-07 13:00 +0100
----
-When using `PTRACE_ATTACH` the `ptrace` mechanism reuses SIGTRAP for a number
-of things by default.
-This makes it unnecessarily hard to distinguish regular traps (possibly caused
-by breakpoints we might place) from other events.
-
-1. After `ptrace(PTRACE_SYSCALL)`, syscall-stops will be reported as SIGTRAPs.
-
- ```c
- int status;
-
- ptrace(PTRACE_SYSCALL, pid, 0, 0);
- waitpid(pid, &status, 0);
-
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
- /* We don't know if the tracee has just entered/exited a syscall or
- * received a regular SIGTRAP (could be caused by a breakpoint we
- * placed). */
- }
- ```
-
- This is fixed by using the `PTRACE_O_TRACESYSGOOD` option.
-
- ```c
- int status;
-
- ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACESYSGOOD);
- ptrace(PTRACE_SYSCALL, pid, 0, 0);
- waitpid(pid, &status, 0);
-
- if (WIFSTOPPED(status) && WSTOPSIG(status) == (SIGTRAP | 0x80)) {
- /* We know for sure that the tracee has just entered/exited a
- * syscall. */
- }
- ```
-
-2. Every `execve` call will be reported as a SIGTRAP.
-
- ```c
- int status;
-
- ptrace(PTRACE_CONT, pid, 0, 0);
- waitpid(pid, &status, 0);
-
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
- /* We don't know if the tracee just called execve() or received a
- * regular SIGTRAP (could be caused by a breakpoint we placed). */
- }
- ```
-
- This is fixed by using the `PTRACE_O_TRACEEXEC` option.
-
- ```c
- int status;
-
- ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACEEXEC);
- ptrace(PTRACE_CONT, pid, 0, 0);
- waitpid(pid, &status, 0);
-
- if (WIFSTOPPED(status) && status >> 8 == (SIGTRAP | PTRACE_EVENT_EXEC << 8)) {
- /* We know for sure that the tracee has just called execve(). */
- }
- ```
-
- This point doesn't apply to tracees attached using `PTRACE_SEIZE`.
- {: .alert .alert-info }
-
-As you can see, you should always use at least the `PTRACE_O_TRACESYSGOOD` and
-`PTRACE_O_TRACEEXEC` options to be able to distinguish between SIGTRAPs.
diff --git a/_posts/2022-11-07-ptrace-waitpid.md b/_posts/2022-11-07-ptrace-waitpid.md
deleted file mode 100644
index b5f34fa..0000000
--- a/_posts/2022-11-07-ptrace-waitpid.md
+++ /dev/null
@@ -1,51 +0,0 @@
----
-title: 'Fun with ptrace: a waitpid pitfall'
-date: 2022-11-07 12:00 +0100
----
-When tracing a process using `ptrace`, one often uses the `waitpid` system call
-to wait until something happens to the tracee.
-It often goes like this (error handling is omitted for brevity):
-
-```c
-/* We have previously attached to tracee `pid`. */
-
-int status;
-
-waitpid(pid, &status, 0);
-
-if (WIFEXITED(status)) {
- /* Tracee has exited. */
-}
-if (WIFSIGNALED(status)) {
- /* Tracee was killed by a signal. */
-}
-/* Tracee was stopped by a signal WSTOPSIG(status). */
-```
-
-What if a single thread is attached to multiple tracees?
-Then we can use `-1` as the first argument to `waitpid`, and it will wait for
-any child to change state.
-
-```c
-int status;
-pid_t pid = waitpid(-1, &status, __WALL);
-```
-
-What's little known, however, is that `waitpid(-1)` will by default consume
-status changes from other thread's children.
-So if you have two tracer threads A and B, and each of them is attached to a
-tracee, then thread A might consume thread B's tracee status change by calling
-`waitpid(-1)`.
-Therefore, thread A would have thread B's tracee status.
-A typical application could be completely unprepared for this scenario.
-
-To avoid that, use the `__WNOTHREAD` flag.
-That way, thread A will only consume status changes from its own children only.
-
-```c
-int status;
-pid_t pid = waitpid(-1, &status, __WALL | __WNOTHREAD);
-```
-
-In my opinion, `__WNOTHREAD` should often be a default in well-structured
-applications.
diff --git a/_posts/snippets/gdb_sleep_all/gdb_sleep_all.sh b/_posts/snippets/gdb_sleep_all/gdb_sleep_all.sh
deleted file mode 100755
index e923740..0000000
--- a/_posts/snippets/gdb_sleep_all/gdb_sleep_all.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-
-set -o errexit -o nounset -o pipefail
-
-# Select all process IDs that are _not_ children of PID 2, [kthreadd].
-pids="$( ps -o pid --no-headers --ppid 2 -p 2 --deselect )"
-
-for pid in $pids; do
- cmdline="$( cat "/proc/$pid/cmdline" | tr '\0' ' ' )" || continue
- echo ------------------------------------------------------------------
- echo "PID: $pid"
- echo "Command line: $cmdline"
- echo ------------------------------------------------------------------
- gdb -p "$pid" -x sleep.gdb -batch &
-done
-
-wait
diff --git a/_posts/snippets/gdb_sleep_all/sleep.gdb b/_posts/snippets/gdb_sleep_all/sleep.gdb
deleted file mode 100644
index 6b8f268..0000000
--- a/_posts/snippets/gdb_sleep_all/sleep.gdb
+++ /dev/null
@@ -1,2 +0,0 @@
-shell sleep 10
-quit
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/shared.hpp
deleted file mode 100644
index 796ea85..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/shared.hpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-inline int shared() {
- static int n = 0;
- return ++n;
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.cpp
deleted file mode 100644
index 330ba80..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "another.hpp"
-
-#include <iostream>
-
-inline void shared() {
- std::cout << "another.cpp: shared()\n";
-}
-
-void another() {
- shared();
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.hpp
deleted file mode 100644
index 9c26d3f..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.hpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-void another();
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/main.cpp
deleted file mode 100644
index e278b9f..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/main.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "another.hpp"
-
-#include <iostream>
-
-inline void shared() {
- std::cout << "main.cpp: shared()\n";
-}
-
-int main() {
- shared();
- another();
- return 0;
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.cpp
deleted file mode 100644
index f13b3a1..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "another.hpp"
-#include "shared.hpp"
-
-void another() {
- Test test;
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.hpp
deleted file mode 100644
index 9c26d3f..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.hpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-void another();
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/main.cpp
deleted file mode 100644
index b3118c1..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/main.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "another.hpp"
-#include "shared.hpp"
-
-int main() {
- Test test;
- another();
- return 0;
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/shared.hpp
deleted file mode 100644
index ef4da34..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/shared.hpp
+++ /dev/null
@@ -1,12 +0,0 @@
-#pragma once
-
-#include <iostream>
-
-struct Test {
- Test();
-};
-
-inline Test::Test() {
- static int x = 0;
- std::cout << ++x << '\n';
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/main.cpp
deleted file mode 100644
index fde1a43..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/main.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "proxy.hpp"
-#include "shared.hpp"
-
-#include <iostream>
-
-int main() {
- std::cout << shared() << '\n';
- std::cout << proxy() << '\n';
- return 0;
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.cpp
deleted file mode 100644
index 78e4611..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "proxy.hpp"
-#include "shared.hpp"
-
-int proxy() {
- return shared();
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.hpp
deleted file mode 100644
index 7dfc52a..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.hpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-int proxy();
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/shared.hpp
deleted file mode 100644
index 647f49e..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/shared.hpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-static int shared() {
- static int n = 0;
- return ++n;
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/main.cpp
deleted file mode 100644
index fde1a43..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/main.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "proxy.hpp"
-#include "shared.hpp"
-
-#include <iostream>
-
-int main() {
- std::cout << shared() << '\n';
- std::cout << proxy() << '\n';
- return 0;
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.cpp
deleted file mode 100644
index 78e4611..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "proxy.hpp"
-#include "shared.hpp"
-
-int proxy() {
- return shared();
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.hpp
deleted file mode 100644
index 7dfc52a..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.hpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-int proxy();
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/shared.hpp
deleted file mode 100644
index 28de441..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/shared.hpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-static inline int shared() {
- static int x = 0;
- return ++x;
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/main.cpp
deleted file mode 100644
index fde1a43..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/main.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "proxy.hpp"
-#include "shared.hpp"
-
-#include <iostream>
-
-int main() {
- std::cout << shared() << '\n';
- std::cout << proxy() << '\n';
- return 0;
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.cpp
deleted file mode 100644
index 78e4611..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "proxy.hpp"
-#include "shared.hpp"
-
-int proxy() {
- return shared();
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.hpp
deleted file mode 100644
index 7dfc52a..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.hpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-int proxy();
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/shared.hpp
deleted file mode 100644
index e21a00c..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/shared.hpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-
-namespace {
-
-inline int shared() {
- static int x = 0;
- return ++x;
-}
-
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.cpp
deleted file mode 100644
index cc7556d..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "another.hpp"
-
-#include <iostream>
-
-namespace {
-
-struct Test {
- Test() {
- std::cout << "another.cpp: Test::Test()\n";
- }
-
- float y = 1.;
-};
-
-}
-
-void another() {
- Test test;
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.hpp
deleted file mode 100644
index 9c26d3f..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.hpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-void another();
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/main.cpp
deleted file mode 100644
index e383ded..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/main.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "another.hpp"
-
-#include <iostream>
-
-namespace {
-
-struct Test {
- Test() {
- std::cout << "main.cpp: Test::Test()\n";
- }
-
- int x = 1;
-};
-
-}
-
-int main() {
- Test test;
- std::cout << test.x << '\n';
- another();
- return 0;
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.cpp
deleted file mode 100644
index 0e0bff9..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "another.hpp"
-
-#include <iostream>
-
-struct Test {
- Test() {
- std::cout << "another.cpp: Test::Test()\n";
- }
-
- float y = 1.;
-};
-
-void another() {
- Test test;
-}
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.hpp
deleted file mode 100644
index 9c26d3f..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.hpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-void another();
diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/main.cpp
deleted file mode 100644
index abd42b7..0000000
--- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/main.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "another.hpp"
-
-#include <iostream>
-
-struct Test {
- Test() {
- std::cout << "main.cpp: Test::Test()\n";
- }
-
- int x = 1;
-};
-
-int main() {
- Test test;
- std::cout << test.x << '\n';
- another();
- return 0;
-}
diff --git a/_posts/snippets/ubuntu_packaging/basic/changelog b/_posts/snippets/ubuntu_packaging/basic/changelog
deleted file mode 100644
index 6b7131e..0000000
--- a/_posts/snippets/ubuntu_packaging/basic/changelog
+++ /dev/null
@@ -1,5 +0,0 @@
-test (1.0-1) unstable; urgency=medium
-
- * Initial release.
-
- -- John Doe <John.Doe@example.com> Wed, 10 Mar 2021 16:15:19 +0000
diff --git a/_posts/snippets/ubuntu_packaging/basic/control b/_posts/snippets/ubuntu_packaging/basic/control
deleted file mode 100644
index 55f8252..0000000
--- a/_posts/snippets/ubuntu_packaging/basic/control
+++ /dev/null
@@ -1,13 +0,0 @@
-Source: test
-Section: utils
-Priority: optional
-Maintainer: John Doe <John.Doe@example.com>
-Build-Depends: debhelper-compat (= 12)
-Standards-Version: 4.4.1
-Homepage: https://example.com/test
-
-Package: test
-Architecture: all
-Depends: ${misc:Depends}
-Description: This is a test package.
- This is a test package, just trying out Debian packaging.
diff --git a/_posts/snippets/ubuntu_packaging/basic/copyright b/_posts/snippets/ubuntu_packaging/basic/copyright
deleted file mode 100644
index 8a67e52..0000000
--- a/_posts/snippets/ubuntu_packaging/basic/copyright
+++ /dev/null
@@ -1,31 +0,0 @@
-Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: test
-Upstream-Contact: John Doe <John.Doe@example.com>
-Source: https://example.com/test
-
-Files: *
-Copyright: 2021 John Doe <John.Doe@example.com>
-License: MIT
-
-Files: debian/*
-Copyright: 2021 John Doe <John.Doe@example.com>
-License: MIT
-
-License: MIT
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
- .
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
- .
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/_posts/snippets/ubuntu_packaging/basic/rules b/_posts/snippets/ubuntu_packaging/basic/rules
deleted file mode 100644
index cbe925d..0000000
--- a/_posts/snippets/ubuntu_packaging/basic/rules
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/bin/make -f
-%:
- dh $@
diff --git a/_posts/snippets/ubuntu_packaging/gbp/gbp.conf b/_posts/snippets/ubuntu_packaging/gbp/gbp.conf
deleted file mode 100644
index d9f7e5f..0000000
--- a/_posts/snippets/ubuntu_packaging/gbp/gbp.conf
+++ /dev/null
@@ -1,5 +0,0 @@
-[DEFAULT]
-upstream-tag = v%(version)s
-debian-branch = debian
-pristine-tar = False
-export-dir = ../build-area/
diff --git a/_posts/snippets/ubuntu_packaging/install/test.install b/_posts/snippets/ubuntu_packaging/install/test.install
deleted file mode 100644
index 6222235..0000000
--- a/_posts/snippets/ubuntu_packaging/install/test.install
+++ /dev/null
@@ -1 +0,0 @@
-test.sh usr/bin