~williamvds/website

5d1ddb50f19693bfd2aca21ce5de579db017b6e0 — williamvds a month ago 6ee5642 linking-by-example
Add Linking by Example
155 files changed, 2238 insertions(+), 0 deletions(-)

A content/blog/linking-by-example/.gitignore
A content/blog/linking-by-example/compilation-with-linking.dot
A content/blog/linking-by-example/export-commits.sh
A content/blog/linking-by-example/exported/Add another source file/CMakeLists.txt
A content/blog/linking-by-example/exported/Add another source file/commit
A content/blog/linking-by-example/exported/Add another source file/library.cpp
A content/blog/linking-by-example/exported/Add another source file/library.hpp
A content/blog/linking-by-example/exported/Add another source file/main.cpp
A content/blog/linking-by-example/exported/Add another source file/results/build log
A content/blog/linking-by-example/exported/Add another source file/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/Add another source file/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/Add another source file/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/Add build script/commit
A content/blog/linking-by-example/exported/C overloading attempt/CMakeLists.txt
A content/blog/linking-by-example/exported/C overloading attempt/commit
A content/blog/linking-by-example/exported/C overloading attempt/library.cpp
A content/blog/linking-by-example/exported/C overloading attempt/library.hpp
A content/blog/linking-by-example/exported/C overloading attempt/main.cpp
A content/blog/linking-by-example/exported/C overloading attempt/results/build log
A content/blog/linking-by-example/exported/C overloading attempt/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/C++ overloading example/CMakeLists.txt
A content/blog/linking-by-example/exported/C++ overloading example/commit
A content/blog/linking-by-example/exported/C++ overloading example/library.cpp
A content/blog/linking-by-example/exported/C++ overloading example/library.hpp
A content/blog/linking-by-example/exported/C++ overloading example/main.cpp
A content/blog/linking-by-example/exported/C++ overloading example/results/build log
A content/blog/linking-by-example/exported/C++ overloading example/results/executable symbols
A content/blog/linking-by-example/exported/C++ overloading example/results/exit code
A content/blog/linking-by-example/exported/C++ overloading example/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/C++ overloading example/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/C++ overloading example/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/Explicit template instantiation/CMakeLists.txt
A content/blog/linking-by-example/exported/Explicit template instantiation/commit
A content/blog/linking-by-example/exported/Explicit template instantiation/library.cpp
A content/blog/linking-by-example/exported/Explicit template instantiation/library.hpp
A content/blog/linking-by-example/exported/Explicit template instantiation/main.cpp
A content/blog/linking-by-example/exported/Explicit template instantiation/results/build log
A content/blog/linking-by-example/exported/Explicit template instantiation/results/executable symbols
A content/blog/linking-by-example/exported/Explicit template instantiation/results/exit code
A content/blog/linking-by-example/exported/Explicit template instantiation/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/Explicit template instantiation/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/Explicit template instantiation/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/Initial example/CMakeLists.txt
A content/blog/linking-by-example/exported/Initial example/commit
A content/blog/linking-by-example/exported/Initial example/main.cpp
A content/blog/linking-by-example/exported/Initial example/results/build log
A content/blog/linking-by-example/exported/Initial example/results/executable symbols
A content/blog/linking-by-example/exported/Initial example/results/exit code
A content/blog/linking-by-example/exported/Initial example/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/Initial example/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/Initial example/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/Make header symbols inline/CMakeLists.txt
A content/blog/linking-by-example/exported/Make header symbols inline/commit
A content/blog/linking-by-example/exported/Make header symbols inline/library.cpp
A content/blog/linking-by-example/exported/Make header symbols inline/library.hpp
A content/blog/linking-by-example/exported/Make header symbols inline/main.cpp
A content/blog/linking-by-example/exported/Make header symbols inline/results/build log
A content/blog/linking-by-example/exported/Make header symbols inline/results/executable symbols
A content/blog/linking-by-example/exported/Make header symbols inline/results/exit code
A content/blog/linking-by-example/exported/Make header symbols inline/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/Make header symbols inline/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/Make header symbols inline/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/Make operand const/CMakeLists.txt
A content/blog/linking-by-example/exported/Make operand const/commit
A content/blog/linking-by-example/exported/Make operand const/main.cpp
A content/blog/linking-by-example/exported/Make operand const/results/build log
A content/blog/linking-by-example/exported/Make operand const/results/executable symbols
A content/blog/linking-by-example/exported/Make operand const/results/exit code
A content/blog/linking-by-example/exported/Make operand const/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/Make operand const/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/Make operand const/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/Move common code into a header file/CMakeLists.txt
A content/blog/linking-by-example/exported/Move common code into a header file/commit
A content/blog/linking-by-example/exported/Move common code into a header file/library.hpp
A content/blog/linking-by-example/exported/Move common code into a header file/main.cpp
A content/blog/linking-by-example/exported/Move common code into a header file/results/build log
A content/blog/linking-by-example/exported/Move common code into a header file/results/executable symbols
A content/blog/linking-by-example/exported/Move common code into a header file/results/exit code
A content/blog/linking-by-example/exported/Move common code into a header file/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/Move common code into a header file/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/Move common code into a header file/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/Move definitions to source file/CMakeLists.txt
A content/blog/linking-by-example/exported/Move definitions to source file/commit
A content/blog/linking-by-example/exported/Move definitions to source file/library.cpp
A content/blog/linking-by-example/exported/Move definitions to source file/library.hpp
A content/blog/linking-by-example/exported/Move definitions to source file/main.cpp
A content/blog/linking-by-example/exported/Move definitions to source file/results/build log
A content/blog/linking-by-example/exported/Move definitions to source file/results/executable symbols
A content/blog/linking-by-example/exported/Move definitions to source file/results/exit code
A content/blog/linking-by-example/exported/Move definitions to source file/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/Move definitions to source file/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/Move definitions to source file/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/Remove extern C/CMakeLists.txt
A content/blog/linking-by-example/exported/Remove extern C/commit
A content/blog/linking-by-example/exported/Remove extern C/library.cpp
A content/blog/linking-by-example/exported/Remove extern C/library.hpp
A content/blog/linking-by-example/exported/Remove extern C/main.cpp
A content/blog/linking-by-example/exported/Remove extern C/results/build log
A content/blog/linking-by-example/exported/Remove extern C/results/executable symbols
A content/blog/linking-by-example/exported/Remove extern C/results/exit code
A content/blog/linking-by-example/exported/Remove extern C/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/Remove extern C/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/Remove extern C/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/Replace with a C++ template/CMakeLists.txt
A content/blog/linking-by-example/exported/Replace with a C++ template/commit
A content/blog/linking-by-example/exported/Replace with a C++ template/library.cpp
A content/blog/linking-by-example/exported/Replace with a C++ template/library.hpp
A content/blog/linking-by-example/exported/Replace with a C++ template/main.cpp
A content/blog/linking-by-example/exported/Replace with a C++ template/results/build log
A content/blog/linking-by-example/exported/Replace with a C++ template/results/executable symbols
A content/blog/linking-by-example/exported/Replace with a C++ template/results/exit code
A content/blog/linking-by-example/exported/Replace with a C++ template/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/Replace with a C++ template/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/Replace with a C++ template/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/Resolve undefined parent class method/CMakeLists.txt
A content/blog/linking-by-example/exported/Resolve undefined parent class method/commit
A content/blog/linking-by-example/exported/Resolve undefined parent class method/library.hpp
A content/blog/linking-by-example/exported/Resolve undefined parent class method/library.tpp
A content/blog/linking-by-example/exported/Resolve undefined parent class method/main.cpp
A content/blog/linking-by-example/exported/Resolve undefined parent class method/other_library.cpp
A content/blog/linking-by-example/exported/Resolve undefined parent class method/other_library.hpp
A content/blog/linking-by-example/exported/Resolve undefined parent class method/results/build log
A content/blog/linking-by-example/exported/Resolve undefined parent class method/results/executable symbols
A content/blog/linking-by-example/exported/Resolve undefined parent class method/results/exit code
A content/blog/linking-by-example/exported/Resolve undefined parent class method/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/Resolve undefined parent class method/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/Resolve undefined parent class method/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/Templated subclass attempt/CMakeLists.txt
A content/blog/linking-by-example/exported/Templated subclass attempt/commit
A content/blog/linking-by-example/exported/Templated subclass attempt/library.cpp
A content/blog/linking-by-example/exported/Templated subclass attempt/library.hpp
A content/blog/linking-by-example/exported/Templated subclass attempt/main.cpp
A content/blog/linking-by-example/exported/Templated subclass attempt/other_library.cpp
A content/blog/linking-by-example/exported/Templated subclass attempt/other_library.hpp
A content/blog/linking-by-example/exported/Templated subclass attempt/results/build log
A content/blog/linking-by-example/exported/Templated subclass attempt/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/Templated subclass attempt/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/Templated subclass attempt/results/other_library.cpp.o symbols
A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/CMakeLists.txt
A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/commit
A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/library.cpp
A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/library.hpp
A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/main.cpp
A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/build log
A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/executable symbols
A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/exit code
A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/library.cpp.o symbols
A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/main.cpp.o symbols
A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/other_library.cpp.o symbols
A content/blog/linking-by-example/index.md
A content/blog/linking-by-example/preprocessor.dot
A content/blog/linking-by-example/simplistic-compilation.dot
M sass/blog.sass
A templates/shortcodes/embed_file.md
A templates/shortcodes/git_commit.html
A content/blog/linking-by-example/.gitignore => content/blog/linking-by-example/.gitignore +1 -0
@@ 0,0 1,1 @@
*.svg

A content/blog/linking-by-example/compilation-with-linking.dot => content/blog/linking-by-example/compilation-with-linking.dot +41 -0
@@ 0,0 1,41 @@
digraph branch {
  bgcolor = transparent
  color = white
  rankdir = LR

  node [fontname="sans-serif" fontsize=12 fontcolor="#eeeeee" color="#eeeeee"]
  edge [fontcolor="#eeeeee" color="#eeeeee" arrowsize=0.8]

  {
    node [shape=none margin=.1 fontname=monospace]
    "main.cpp"
    "source.cpp"
    extra1 [label="..."]
    extra1

    "main.o"
    "source.o"
    extra2 [label="..."]

    executable
  }

  {
    node [shape=box]

    {
      node [label="compiler"]
      compiler1
      compiler2
      compiler3
    }

    linker
  }

  "main.cpp" -> compiler1 -> "main.o" -> linker
  "source.cpp" -> compiler2 -> "source.o" -> linker
  extra1 -> compiler3 -> extra2 -> linker

  linker -> executable
}

A content/blog/linking-by-example/export-commits.sh => content/blog/linking-by-example/export-commits.sh +28 -0
@@ 0,0 1,28 @@
#!/usr/bin/env bash
# Export the files and diffs from commits in the provided repository

set -eu -o pipefail

export_root="$(readlink -f "${2:-.}"/exported)"

mkdir -p "$export_root"
rm -rf "${export_root:?}/*"

function export_git() {
  cd "$1"

  git rev-list --no-commit-header --format=$'%H\n%s' HEAD |
    while read -r commit; do
      IFS= read -r subject
      >&2 echo "exporting commit $commit $subject"
      export="$export_root/$subject"
      mkdir "$export"
      git archive "$commit" --format=tar \
        | tar --extract --directory "$export"
      echo "$commit" > "$export_root/$subject/commit"
    done
}


>&2 echo "exporting $1 to $export_root"
export_git "$1"

A content/blog/linking-by-example/exported/Add another source file/CMakeLists.txt => content/blog/linking-by-example/exported/Add another source file/CMakeLists.txt +10 -0
@@ 0,0 1,10 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    library.cpp
    main.cpp
)

A content/blog/linking-by-example/exported/Add another source file/commit => content/blog/linking-by-example/exported/Add another source file/commit +1 -0
@@ 0,0 1,1 @@
3eab681ee4e129df17c904af763e612ee3914d30

A content/blog/linking-by-example/exported/Add another source file/library.cpp => content/blog/linking-by-example/exported/Add another source file/library.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int square_10() {
    return square(10);
}

A content/blog/linking-by-example/exported/Add another source file/library.hpp => content/blog/linking-by-example/exported/Add another source file/library.hpp +11 -0
@@ 0,0 1,11 @@
#pragma once

extern "C" {

int square(int num) {
    return num * num;
}

int operand = 5;

} // extern "C"

A content/blog/linking-by-example/exported/Add another source file/main.cpp => content/blog/linking-by-example/exported/Add another source file/main.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int main() {
    return square(operand);
}

A content/blog/linking-by-example/exported/Add another source file/results/build log => content/blog/linking-by-example/exported/Add another source file/results/build log +15 -0
@@ 0,0 1,15 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/3] Building CXX object CMakeFiles/example.dir/main.cpp.o
[2/3] Building CXX object CMakeFiles/example.dir/library.cpp.o
[3/3] Linking CXX executable example
FAILED: example 
: && /usr/bin/c++   CMakeFiles/example.dir/library.cpp.o CMakeFiles/example.dir/main.cpp.o -o example   && :
/usr/bin/ld: CMakeFiles/example.dir/main.cpp.o: in function `square':
main.cpp:(.text+0x0): multiple definition of `square'; CMakeFiles/example.dir/library.cpp.o:library.cpp:(.text+0x0): first defined here
/usr/bin/ld: CMakeFiles/example.dir/main.cpp.o:(.data+0x0): multiple definition of `operand'; CMakeFiles/example.dir/library.cpp.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

A content/blog/linking-by-example/exported/Add another source file/results/library.cpp.o symbols => content/blog/linking-by-example/exported/Add another source file/results/library.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o
0000000000000000 D operand
0000000000000000 T square
000000000000000f T square_10()

A content/blog/linking-by-example/exported/Add another source file/results/main.cpp.o symbols => content/blog/linking-by-example/exported/Add another source file/results/main.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
000000000000000f T main
0000000000000000 D operand
0000000000000000 T square

A content/blog/linking-by-example/exported/Add another source file/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/Add another source file/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Add build script/commit => content/blog/linking-by-example/exported/Add build script/commit +1 -0
@@ 0,0 1,1 @@
b4793f8eb6cb9d15ef54c7fd99fc3d39dcd1fd62

A content/blog/linking-by-example/exported/C overloading attempt/CMakeLists.txt => content/blog/linking-by-example/exported/C overloading attempt/CMakeLists.txt +10 -0
@@ 0,0 1,10 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    library.cpp
    main.cpp
)

A content/blog/linking-by-example/exported/C overloading attempt/commit => content/blog/linking-by-example/exported/C overloading attempt/commit +1 -0
@@ 0,0 1,1 @@
39cfc50e943f4ff683974db5ab789fe32ad66b53

A content/blog/linking-by-example/exported/C overloading attempt/library.cpp => content/blog/linking-by-example/exported/C overloading attempt/library.cpp +19 -0
@@ 0,0 1,19 @@
#include "library.hpp"

extern "C" {

long square(int num) {
    return num * num;
}

long square(long num) {
    return num * num;
}

} // extern "C"

int operand = 5;

int square_10() {
    return square(10);
}

A content/blog/linking-by-example/exported/C overloading attempt/library.hpp => content/blog/linking-by-example/exported/C overloading attempt/library.hpp +10 -0
@@ 0,0 1,10 @@
#pragma once

extern "C" {

long square(int num);
long square(long num);

} // extern "C"

extern int operand;

A content/blog/linking-by-example/exported/C overloading attempt/main.cpp => content/blog/linking-by-example/exported/C overloading attempt/main.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int main() {
    return square(static_cast<long>(operand));
}

A content/blog/linking-by-example/exported/C overloading attempt/results/build log => content/blog/linking-by-example/exported/C overloading attempt/results/build log +32 -0
@@ 0,0 1,32 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/3] Building CXX object CMakeFiles/example.dir/main.cpp.o
FAILED: CMakeFiles/example.dir/main.cpp.o 
/usr/bin/c++    -MD -MT CMakeFiles/example.dir/main.cpp.o -MF CMakeFiles/example.dir/main.cpp.o.d -o CMakeFiles/example.dir/main.cpp.o -c /home/william/scratch/public/linking-by-example/main.cpp
In file included from /home/william/scratch/public/linking-by-example/main.cpp:1:
/home/william/scratch/public/linking-by-example/library.hpp:6:6: error: conflicting declaration of C function ‘long int square(long int)’
    6 | long square(long num);
      |      ^~~~~~
/home/william/scratch/public/linking-by-example/library.hpp:5:6: note: previous declaration ‘long int square(int)’
    5 | long square(int num);
      |      ^~~~~~
[2/3] Building CXX object CMakeFiles/example.dir/library.cpp.o
FAILED: CMakeFiles/example.dir/library.cpp.o 
/usr/bin/c++    -MD -MT CMakeFiles/example.dir/library.cpp.o -MF CMakeFiles/example.dir/library.cpp.o.d -o CMakeFiles/example.dir/library.cpp.o -c /home/william/scratch/public/linking-by-example/library.cpp
In file included from /home/william/scratch/public/linking-by-example/library.cpp:1:
/home/william/scratch/public/linking-by-example/library.hpp:6:6: error: conflicting declaration of C function ‘long int square(long int)’
    6 | long square(long num);
      |      ^~~~~~
/home/william/scratch/public/linking-by-example/library.hpp:5:6: note: previous declaration ‘long int square(int)’
    5 | long square(int num);
      |      ^~~~~~
/home/william/scratch/public/linking-by-example/library.cpp:9:6: error: conflicting declaration of C function ‘long int square(long int)’
    9 | long square(long num) {
      |      ^~~~~~
/home/william/scratch/public/linking-by-example/library.cpp:5:6: note: previous declaration ‘long int square(int)’
    5 | long square(int num) {
      |      ^~~~~~
ninja: build stopped: subcommand failed.

A content/blog/linking-by-example/exported/C overloading attempt/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/C overloading attempt/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/C++ overloading example/CMakeLists.txt => content/blog/linking-by-example/exported/C++ overloading example/CMakeLists.txt +10 -0
@@ 0,0 1,10 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    library.cpp
    main.cpp
)

A content/blog/linking-by-example/exported/C++ overloading example/commit => content/blog/linking-by-example/exported/C++ overloading example/commit +1 -0
@@ 0,0 1,1 @@
9e7dab9b895bb72c86c053f2d4e4c42346ebac19

A content/blog/linking-by-example/exported/C++ overloading example/library.cpp => content/blog/linking-by-example/exported/C++ overloading example/library.cpp +19 -0
@@ 0,0 1,19 @@
#include "library.hpp"

namespace my::library {

int square(int num) {
    return num * num;
}

long square(long num) {
    return num * num;
}

int operand = 5;

int square_10() {
    return square(10);
}

} // namespace my::library

A content/blog/linking-by-example/exported/C++ overloading example/library.hpp => content/blog/linking-by-example/exported/C++ overloading example/library.hpp +10 -0
@@ 0,0 1,10 @@
#pragma once

namespace my::library {

int square(int num);
long square(long num);

extern int operand;

} // namespace my::library

A content/blog/linking-by-example/exported/C++ overloading example/main.cpp => content/blog/linking-by-example/exported/C++ overloading example/main.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int main() {
    return my::library::square(static_cast<long>(my::library::operand));
}

A content/blog/linking-by-example/exported/C++ overloading example/results/build log => content/blog/linking-by-example/exported/C++ overloading example/results/build log +8 -0
@@ 0,0 1,8 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/3] Building CXX object CMakeFiles/example.dir/main.cpp.o
[2/3] Building CXX object CMakeFiles/example.dir/library.cpp.o
[3/3] Linking CXX executable example

A content/blog/linking-by-example/exported/C++ overloading example/results/executable symbols => content/blog/linking-by-example/exported/C++ overloading example/results/executable symbols +25 -0
@@ 0,0 1,25 @@
$ nm --demangle ./build/example
0000000000004014 B __bss_start
                 w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
0000000000004008 D __dso_handle
0000000000003df0 d _DYNAMIC
0000000000004014 D _edata
0000000000004018 B _end
0000000000001160 T _fini
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U __libc_start_main@GLIBC_2.34
000000000000114a T main
0000000000001020 T _start
0000000000004018 D __TMC_END__
0000000000001119 T my::library::square(int)
0000000000001128 T my::library::square(long)
0000000000004010 D my::library::operand
000000000000113a T my::library::square_10()

A content/blog/linking-by-example/exported/C++ overloading example/results/exit code => content/blog/linking-by-example/exported/C++ overloading example/results/exit code +1 -0
@@ 0,0 1,1 @@
25

A content/blog/linking-by-example/exported/C++ overloading example/results/library.cpp.o symbols => content/blog/linking-by-example/exported/C++ overloading example/results/library.cpp.o symbols +5 -0
@@ 0,0 1,5 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o
0000000000000000 T my::library::square(int)
000000000000000f T my::library::square(long)
0000000000000000 D my::library::operand
0000000000000021 T my::library::square_10()

A content/blog/linking-by-example/exported/C++ overloading example/results/main.cpp.o symbols => content/blog/linking-by-example/exported/C++ overloading example/results/main.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
0000000000000000 T main
                 U my::library::square(long)
                 U my::library::operand

A content/blog/linking-by-example/exported/C++ overloading example/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/C++ overloading example/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Explicit template instantiation/CMakeLists.txt => content/blog/linking-by-example/exported/Explicit template instantiation/CMakeLists.txt +10 -0
@@ 0,0 1,10 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    library.cpp
    main.cpp
)

A content/blog/linking-by-example/exported/Explicit template instantiation/commit => content/blog/linking-by-example/exported/Explicit template instantiation/commit +1 -0
@@ 0,0 1,1 @@
343d4246dc4baa508e048f78c96e10329e657b08

A content/blog/linking-by-example/exported/Explicit template instantiation/library.cpp => content/blog/linking-by-example/exported/Explicit template instantiation/library.cpp +15 -0
@@ 0,0 1,15 @@
#include "library.hpp"

template <typename T>
T square(T num) {
    return num * num;
}

template int square<>(int);
template long square<>(long);

int operand = 5;

int square_10() {
    return square(10);
}

A content/blog/linking-by-example/exported/Explicit template instantiation/library.hpp => content/blog/linking-by-example/exported/Explicit template instantiation/library.hpp +6 -0
@@ 0,0 1,6 @@
#pragma once

template <typename T>
extern T square(T num);

extern int operand;

A content/blog/linking-by-example/exported/Explicit template instantiation/main.cpp => content/blog/linking-by-example/exported/Explicit template instantiation/main.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int main() {
    return square(static_cast<long>(operand));
}

A content/blog/linking-by-example/exported/Explicit template instantiation/results/build log => content/blog/linking-by-example/exported/Explicit template instantiation/results/build log +8 -0
@@ 0,0 1,8 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/3] Building CXX object CMakeFiles/example.dir/main.cpp.o
[2/3] Building CXX object CMakeFiles/example.dir/library.cpp.o
[3/3] Linking CXX executable example

A content/blog/linking-by-example/exported/Explicit template instantiation/results/executable symbols => content/blog/linking-by-example/exported/Explicit template instantiation/results/executable symbols +25 -0
@@ 0,0 1,25 @@
$ nm --demangle ./build/example
0000000000004014 B __bss_start
                 w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
0000000000004008 D __dso_handle
0000000000003df0 d _DYNAMIC
0000000000004014 D _edata
0000000000004018 B _end
0000000000001160 T _fini
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U __libc_start_main@GLIBC_2.34
000000000000114a T main
0000000000004010 D operand
0000000000001020 T _start
0000000000004018 D __TMC_END__
0000000000001129 W int square<int>(int)
0000000000001138 W long square<long>(long)
0000000000001119 T square_10()

A content/blog/linking-by-example/exported/Explicit template instantiation/results/exit code => content/blog/linking-by-example/exported/Explicit template instantiation/results/exit code +1 -0
@@ 0,0 1,1 @@
25

A content/blog/linking-by-example/exported/Explicit template instantiation/results/library.cpp.o symbols => content/blog/linking-by-example/exported/Explicit template instantiation/results/library.cpp.o symbols +5 -0
@@ 0,0 1,5 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o
0000000000000000 D operand
0000000000000000 W int square<int>(int)
0000000000000000 W long square<long>(long)
0000000000000000 T square_10()

A content/blog/linking-by-example/exported/Explicit template instantiation/results/main.cpp.o symbols => content/blog/linking-by-example/exported/Explicit template instantiation/results/main.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
0000000000000000 T main
                 U operand
                 U long square<long>(long)

A content/blog/linking-by-example/exported/Explicit template instantiation/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/Explicit template instantiation/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Initial example/CMakeLists.txt => content/blog/linking-by-example/exported/Initial example/CMakeLists.txt +9 -0
@@ 0,0 1,9 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    main.cpp
)

A content/blog/linking-by-example/exported/Initial example/commit => content/blog/linking-by-example/exported/Initial example/commit +1 -0
@@ 0,0 1,1 @@
5ec3b5f2912da1e6533fe6374c5ffce551a8b26b

A content/blog/linking-by-example/exported/Initial example/main.cpp => content/blog/linking-by-example/exported/Initial example/main.cpp +13 -0
@@ 0,0 1,13 @@
extern "C" {

int square(int num) {
    return num * num;
}

int operand = 5;

}

int main() {
    return square(operand);
}

A content/blog/linking-by-example/exported/Initial example/results/build log => content/blog/linking-by-example/exported/Initial example/results/build log +7 -0
@@ 0,0 1,7 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/2] Building CXX object CMakeFiles/example.dir/main.cpp.o
[2/2] Linking CXX executable example

A content/blog/linking-by-example/exported/Initial example/results/executable symbols => content/blog/linking-by-example/exported/Initial example/results/executable symbols +23 -0
@@ 0,0 1,23 @@
$ nm --demangle ./build/example
0000000000004014 B __bss_start
                 w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
0000000000004008 D __dso_handle
0000000000003df0 d _DYNAMIC
0000000000004014 D _edata
0000000000004018 B _end
000000000000113c T _fini
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U __libc_start_main@GLIBC_2.34
0000000000001128 T main
0000000000004010 D operand
0000000000001119 T square
0000000000001020 T _start
0000000000004018 D __TMC_END__

A content/blog/linking-by-example/exported/Initial example/results/exit code => content/blog/linking-by-example/exported/Initial example/results/exit code +1 -0
@@ 0,0 1,1 @@
25

A content/blog/linking-by-example/exported/Initial example/results/library.cpp.o symbols => content/blog/linking-by-example/exported/Initial example/results/library.cpp.o symbols +1 -0
@@ 0,0 1,1 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o

A content/blog/linking-by-example/exported/Initial example/results/main.cpp.o symbols => content/blog/linking-by-example/exported/Initial example/results/main.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
000000000000000f T main
0000000000000000 D operand
0000000000000000 T square

A content/blog/linking-by-example/exported/Initial example/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/Initial example/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Make header symbols inline/CMakeLists.txt => content/blog/linking-by-example/exported/Make header symbols inline/CMakeLists.txt +10 -0
@@ 0,0 1,10 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    library.cpp
    main.cpp
)

A content/blog/linking-by-example/exported/Make header symbols inline/commit => content/blog/linking-by-example/exported/Make header symbols inline/commit +1 -0
@@ 0,0 1,1 @@
93725c2f7c48a7d57fe18f5b7b81277824e798ac

A content/blog/linking-by-example/exported/Make header symbols inline/library.cpp => content/blog/linking-by-example/exported/Make header symbols inline/library.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int square_10() {
    return square(10);
}

A content/blog/linking-by-example/exported/Make header symbols inline/library.hpp => content/blog/linking-by-example/exported/Make header symbols inline/library.hpp +11 -0
@@ 0,0 1,11 @@
#pragma once

extern "C" {

inline int square(int num) {
    return num * num;
}

inline int operand = 5;

} // extern "C"

A content/blog/linking-by-example/exported/Make header symbols inline/main.cpp => content/blog/linking-by-example/exported/Make header symbols inline/main.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int main() {
    return square(operand);
}

A content/blog/linking-by-example/exported/Make header symbols inline/results/build log => content/blog/linking-by-example/exported/Make header symbols inline/results/build log +8 -0
@@ 0,0 1,8 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/3] Building CXX object CMakeFiles/example.dir/library.cpp.o
[2/3] Building CXX object CMakeFiles/example.dir/main.cpp.o
[3/3] Linking CXX executable example

A content/blog/linking-by-example/exported/Make header symbols inline/results/executable symbols => content/blog/linking-by-example/exported/Make header symbols inline/results/executable symbols +24 -0
@@ 0,0 1,24 @@
$ nm --demangle ./build/example
0000000000004014 B __bss_start
                 w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
0000000000004008 D __dso_handle
0000000000003df0 d _DYNAMIC
0000000000004014 D _edata
0000000000004018 B _end
000000000000114c T _fini
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U __libc_start_main@GLIBC_2.34
0000000000001138 T main
0000000000004010 u operand
0000000000001129 W square
0000000000001020 T _start
0000000000004018 D __TMC_END__
0000000000001119 T square_10()

A content/blog/linking-by-example/exported/Make header symbols inline/results/exit code => content/blog/linking-by-example/exported/Make header symbols inline/results/exit code +1 -0
@@ 0,0 1,1 @@
25

A content/blog/linking-by-example/exported/Make header symbols inline/results/library.cpp.o symbols => content/blog/linking-by-example/exported/Make header symbols inline/results/library.cpp.o symbols +3 -0
@@ 0,0 1,3 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o
0000000000000000 W square
0000000000000000 T square_10()

A content/blog/linking-by-example/exported/Make header symbols inline/results/main.cpp.o symbols => content/blog/linking-by-example/exported/Make header symbols inline/results/main.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
0000000000000000 T main
0000000000000000 u operand
0000000000000000 W square

A content/blog/linking-by-example/exported/Make header symbols inline/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/Make header symbols inline/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Make operand const/CMakeLists.txt => content/blog/linking-by-example/exported/Make operand const/CMakeLists.txt +9 -0
@@ 0,0 1,9 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    main.cpp
)

A content/blog/linking-by-example/exported/Make operand const/commit => content/blog/linking-by-example/exported/Make operand const/commit +1 -0
@@ 0,0 1,1 @@
edc20aec06c0861966996db2dea33a579a94d7f3

A content/blog/linking-by-example/exported/Make operand const/main.cpp => content/blog/linking-by-example/exported/Make operand const/main.cpp +13 -0
@@ 0,0 1,13 @@
extern "C" {

int square(int num) {
    return num * num;
}

const int operand = 5;

}

int main() {
    return square(operand);
}

A content/blog/linking-by-example/exported/Make operand const/results/build log => content/blog/linking-by-example/exported/Make operand const/results/build log +7 -0
@@ 0,0 1,7 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/2] Building CXX object CMakeFiles/example.dir/main.cpp.o
[2/2] Linking CXX executable example

A content/blog/linking-by-example/exported/Make operand const/results/executable symbols => content/blog/linking-by-example/exported/Make operand const/results/executable symbols +23 -0
@@ 0,0 1,23 @@
$ nm --demangle ./build/example
0000000000004010 B __bss_start
                 w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
0000000000004008 D __dso_handle
0000000000003df0 d _DYNAMIC
0000000000004010 D _edata
0000000000004018 B _end
000000000000113c T _fini
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002008 r __GNU_EH_FRAME_HDR
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U __libc_start_main@GLIBC_2.34
0000000000001128 T main
0000000000001119 T square
0000000000001020 T _start
0000000000004010 D __TMC_END__
0000000000002004 r operand

A content/blog/linking-by-example/exported/Make operand const/results/exit code => content/blog/linking-by-example/exported/Make operand const/results/exit code +1 -0
@@ 0,0 1,1 @@
25

A content/blog/linking-by-example/exported/Make operand const/results/library.cpp.o symbols => content/blog/linking-by-example/exported/Make operand const/results/library.cpp.o symbols +1 -0
@@ 0,0 1,1 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o

A content/blog/linking-by-example/exported/Make operand const/results/main.cpp.o symbols => content/blog/linking-by-example/exported/Make operand const/results/main.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
000000000000000f T main
0000000000000000 T square
0000000000000000 r operand

A content/blog/linking-by-example/exported/Make operand const/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/Make operand const/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Move common code into a header file/CMakeLists.txt => content/blog/linking-by-example/exported/Move common code into a header file/CMakeLists.txt +9 -0
@@ 0,0 1,9 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    main.cpp
)

A content/blog/linking-by-example/exported/Move common code into a header file/commit => content/blog/linking-by-example/exported/Move common code into a header file/commit +1 -0
@@ 0,0 1,1 @@
58e3d1a090f92394f57700da7e0fac4f902fde9d

A content/blog/linking-by-example/exported/Move common code into a header file/library.hpp => content/blog/linking-by-example/exported/Move common code into a header file/library.hpp +11 -0
@@ 0,0 1,11 @@
#pragma once

extern "C" {

int square(int num) {
    return num * num;
}

int operand = 5;

} // extern "C"

A content/blog/linking-by-example/exported/Move common code into a header file/main.cpp => content/blog/linking-by-example/exported/Move common code into a header file/main.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int main() {
    return square(operand);
}

A content/blog/linking-by-example/exported/Move common code into a header file/results/build log => content/blog/linking-by-example/exported/Move common code into a header file/results/build log +7 -0
@@ 0,0 1,7 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/2] Building CXX object CMakeFiles/example.dir/main.cpp.o
[2/2] Linking CXX executable example

A content/blog/linking-by-example/exported/Move common code into a header file/results/executable symbols => content/blog/linking-by-example/exported/Move common code into a header file/results/executable symbols +23 -0
@@ 0,0 1,23 @@
$ nm --demangle ./build/example
0000000000004014 B __bss_start
                 w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
0000000000004008 D __dso_handle
0000000000003df0 d _DYNAMIC
0000000000004014 D _edata
0000000000004018 B _end
000000000000113c T _fini
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U __libc_start_main@GLIBC_2.34
0000000000001128 T main
0000000000004010 D operand
0000000000001119 T square
0000000000001020 T _start
0000000000004018 D __TMC_END__

A content/blog/linking-by-example/exported/Move common code into a header file/results/exit code => content/blog/linking-by-example/exported/Move common code into a header file/results/exit code +1 -0
@@ 0,0 1,1 @@
25

A content/blog/linking-by-example/exported/Move common code into a header file/results/library.cpp.o symbols => content/blog/linking-by-example/exported/Move common code into a header file/results/library.cpp.o symbols +1 -0
@@ 0,0 1,1 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o

A content/blog/linking-by-example/exported/Move common code into a header file/results/main.cpp.o symbols => content/blog/linking-by-example/exported/Move common code into a header file/results/main.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
000000000000000f T main
0000000000000000 D operand
0000000000000000 T square

A content/blog/linking-by-example/exported/Move common code into a header file/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/Move common code into a header file/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Move definitions to source file/CMakeLists.txt => content/blog/linking-by-example/exported/Move definitions to source file/CMakeLists.txt +10 -0
@@ 0,0 1,10 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    library.cpp
    main.cpp
)

A content/blog/linking-by-example/exported/Move definitions to source file/commit => content/blog/linking-by-example/exported/Move definitions to source file/commit +1 -0
@@ 0,0 1,1 @@
73d3221fe0b98004fff35e14173fa5b80cf38eab

A content/blog/linking-by-example/exported/Move definitions to source file/library.cpp => content/blog/linking-by-example/exported/Move definitions to source file/library.cpp +15 -0
@@ 0,0 1,15 @@
#include "library.hpp"

extern "C" {

int square(int num) {
    return num * num;
}

int operand = 5;

} // extern "C"

int square_10() {
    return square(10);
}

A content/blog/linking-by-example/exported/Move definitions to source file/library.hpp => content/blog/linking-by-example/exported/Move definitions to source file/library.hpp +9 -0
@@ 0,0 1,9 @@
#pragma once

extern "C" {

int square(int num);

extern int operand;

} // extern "C"

A content/blog/linking-by-example/exported/Move definitions to source file/main.cpp => content/blog/linking-by-example/exported/Move definitions to source file/main.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int main() {
    return square(operand);
}

A content/blog/linking-by-example/exported/Move definitions to source file/results/build log => content/blog/linking-by-example/exported/Move definitions to source file/results/build log +8 -0
@@ 0,0 1,8 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/3] Building CXX object CMakeFiles/example.dir/main.cpp.o
[2/3] Building CXX object CMakeFiles/example.dir/library.cpp.o
[3/3] Linking CXX executable example

A content/blog/linking-by-example/exported/Move definitions to source file/results/executable symbols => content/blog/linking-by-example/exported/Move definitions to source file/results/executable symbols +24 -0
@@ 0,0 1,24 @@
$ nm --demangle ./build/example
0000000000004014 B __bss_start
                 w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
0000000000004008 D __dso_handle
0000000000003df0 d _DYNAMIC
0000000000004014 D _edata
0000000000004018 B _end
000000000000114c T _fini
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U __libc_start_main@GLIBC_2.34
0000000000001138 T main
0000000000004010 D operand
0000000000001119 T square
0000000000001020 T _start
0000000000004018 D __TMC_END__
0000000000001128 T square_10()

A content/blog/linking-by-example/exported/Move definitions to source file/results/exit code => content/blog/linking-by-example/exported/Move definitions to source file/results/exit code +1 -0
@@ 0,0 1,1 @@
25

A content/blog/linking-by-example/exported/Move definitions to source file/results/library.cpp.o symbols => content/blog/linking-by-example/exported/Move definitions to source file/results/library.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o
0000000000000000 D operand
0000000000000000 T square
000000000000000f T square_10()

A content/blog/linking-by-example/exported/Move definitions to source file/results/main.cpp.o symbols => content/blog/linking-by-example/exported/Move definitions to source file/results/main.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
0000000000000000 T main
                 U operand
                 U square

A content/blog/linking-by-example/exported/Move definitions to source file/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/Move definitions to source file/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Remove extern C/CMakeLists.txt => content/blog/linking-by-example/exported/Remove extern C/CMakeLists.txt +10 -0
@@ 0,0 1,10 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    library.cpp
    main.cpp
)

A content/blog/linking-by-example/exported/Remove extern C/commit => content/blog/linking-by-example/exported/Remove extern C/commit +1 -0
@@ 0,0 1,1 @@
b544fe3adbecb60dd93bfe989604b9c40207d562

A content/blog/linking-by-example/exported/Remove extern C/library.cpp => content/blog/linking-by-example/exported/Remove extern C/library.cpp +11 -0
@@ 0,0 1,11 @@
#include "library.hpp"

int square(int num) {
    return num * num;
}

int operand = 5;

int square_10() {
    return square(10);
}

A content/blog/linking-by-example/exported/Remove extern C/library.hpp => content/blog/linking-by-example/exported/Remove extern C/library.hpp +5 -0
@@ 0,0 1,5 @@
#pragma once

int square(int num);

extern int operand;

A content/blog/linking-by-example/exported/Remove extern C/main.cpp => content/blog/linking-by-example/exported/Remove extern C/main.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int main() {
    return square(operand);
}

A content/blog/linking-by-example/exported/Remove extern C/results/build log => content/blog/linking-by-example/exported/Remove extern C/results/build log +8 -0
@@ 0,0 1,8 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/3] Building CXX object CMakeFiles/example.dir/main.cpp.o
[2/3] Building CXX object CMakeFiles/example.dir/library.cpp.o
[3/3] Linking CXX executable example

A content/blog/linking-by-example/exported/Remove extern C/results/executable symbols => content/blog/linking-by-example/exported/Remove extern C/results/executable symbols +24 -0
@@ 0,0 1,24 @@
$ nm --demangle ./build/example
0000000000004014 B __bss_start
                 w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
0000000000004008 D __dso_handle
0000000000003df0 d _DYNAMIC
0000000000004014 D _edata
0000000000004018 B _end
000000000000114c T _fini
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U __libc_start_main@GLIBC_2.34
0000000000001138 T main
0000000000004010 D operand
0000000000001020 T _start
0000000000004018 D __TMC_END__
0000000000001119 T square(int)
0000000000001128 T square_10()

A content/blog/linking-by-example/exported/Remove extern C/results/exit code => content/blog/linking-by-example/exported/Remove extern C/results/exit code +1 -0
@@ 0,0 1,1 @@
25

A content/blog/linking-by-example/exported/Remove extern C/results/library.cpp.o symbols => content/blog/linking-by-example/exported/Remove extern C/results/library.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o
0000000000000000 D operand
0000000000000000 T square(int)
000000000000000f T square_10()

A content/blog/linking-by-example/exported/Remove extern C/results/main.cpp.o symbols => content/blog/linking-by-example/exported/Remove extern C/results/main.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
0000000000000000 T main
                 U operand
                 U square(int)

A content/blog/linking-by-example/exported/Remove extern C/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/Remove extern C/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Replace with a C++ template/CMakeLists.txt => content/blog/linking-by-example/exported/Replace with a C++ template/CMakeLists.txt +10 -0
@@ 0,0 1,10 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    library.cpp
    main.cpp
)

A content/blog/linking-by-example/exported/Replace with a C++ template/commit => content/blog/linking-by-example/exported/Replace with a C++ template/commit +1 -0
@@ 0,0 1,1 @@
624f9f1124a8a828d2a40f221e8805e7411d425e

A content/blog/linking-by-example/exported/Replace with a C++ template/library.cpp => content/blog/linking-by-example/exported/Replace with a C++ template/library.cpp +7 -0
@@ 0,0 1,7 @@
#include "library.hpp"

int operand = 5;

int square_10() {
    return square(10);
}

A content/blog/linking-by-example/exported/Replace with a C++ template/library.hpp => content/blog/linking-by-example/exported/Replace with a C++ template/library.hpp +8 -0
@@ 0,0 1,8 @@
#pragma once

template <typename T>
auto square(T num) {
    return num * num;
}

extern int operand;

A content/blog/linking-by-example/exported/Replace with a C++ template/main.cpp => content/blog/linking-by-example/exported/Replace with a C++ template/main.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int main() {
    return square(static_cast<long>(operand));
}

A content/blog/linking-by-example/exported/Replace with a C++ template/results/build log => content/blog/linking-by-example/exported/Replace with a C++ template/results/build log +8 -0
@@ 0,0 1,8 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/3] Building CXX object CMakeFiles/example.dir/main.cpp.o
[2/3] Building CXX object CMakeFiles/example.dir/library.cpp.o
[3/3] Linking CXX executable example

A content/blog/linking-by-example/exported/Replace with a C++ template/results/executable symbols => content/blog/linking-by-example/exported/Replace with a C++ template/results/executable symbols +25 -0
@@ 0,0 1,25 @@
$ nm --demangle ./build/example
0000000000004014 B __bss_start
                 w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
0000000000004008 D __dso_handle
0000000000003df0 d _DYNAMIC
0000000000004014 D _edata
0000000000004018 B _end
0000000000001160 T _fini
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U __libc_start_main@GLIBC_2.34
0000000000001138 T main
0000000000004010 D operand
0000000000001020 T _start
0000000000004018 D __TMC_END__
0000000000001129 W auto square<int>(int)
000000000000114e W auto square<long>(long)
0000000000001119 T square_10()

A content/blog/linking-by-example/exported/Replace with a C++ template/results/exit code => content/blog/linking-by-example/exported/Replace with a C++ template/results/exit code +1 -0
@@ 0,0 1,1 @@
25

A content/blog/linking-by-example/exported/Replace with a C++ template/results/library.cpp.o symbols => content/blog/linking-by-example/exported/Replace with a C++ template/results/library.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o
0000000000000000 D operand
0000000000000000 W auto square<int>(int)
0000000000000000 T square_10()

A content/blog/linking-by-example/exported/Replace with a C++ template/results/main.cpp.o symbols => content/blog/linking-by-example/exported/Replace with a C++ template/results/main.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
0000000000000000 T main
                 U operand
0000000000000000 W auto square<long>(long)

A content/blog/linking-by-example/exported/Replace with a C++ template/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/Replace with a C++ template/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Resolve undefined parent class method/CMakeLists.txt => content/blog/linking-by-example/exported/Resolve undefined parent class method/CMakeLists.txt +10 -0
@@ 0,0 1,10 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    other_library.cpp
    main.cpp
)

A content/blog/linking-by-example/exported/Resolve undefined parent class method/commit => content/blog/linking-by-example/exported/Resolve undefined parent class method/commit +1 -0
@@ 0,0 1,1 @@
8757c7370d2a9f29b5b6414275325819d9fc69bc

A content/blog/linking-by-example/exported/Resolve undefined parent class method/library.hpp => content/blog/linking-by-example/exported/Resolve undefined parent class method/library.hpp +10 -0
@@ 0,0 1,10 @@
#pragma once

template <typename T>
class TemplatedClass
{
public:
    virtual ~TemplatedClass() = default;

    virtual int method();
};

A content/blog/linking-by-example/exported/Resolve undefined parent class method/library.tpp => content/blog/linking-by-example/exported/Resolve undefined parent class method/library.tpp +4 -0
@@ 0,0 1,4 @@
#include "library.hpp"

template <typename T>
int TemplatedClass<T>::method() { return 42; }

A content/blog/linking-by-example/exported/Resolve undefined parent class method/main.cpp => content/blog/linking-by-example/exported/Resolve undefined parent class method/main.cpp +5 -0
@@ 0,0 1,5 @@
#include "other_library.hpp"

int main() {
    return ChildClass<int>{}.method();
}

A content/blog/linking-by-example/exported/Resolve undefined parent class method/other_library.cpp => content/blog/linking-by-example/exported/Resolve undefined parent class method/other_library.cpp +8 -0
@@ 0,0 1,8 @@
#include "other_library.hpp"

#include "library.tpp"

template <typename T>
int ChildClass<T>::method() { return 1; }

template class ChildClass<int>;

A content/blog/linking-by-example/exported/Resolve undefined parent class method/other_library.hpp => content/blog/linking-by-example/exported/Resolve undefined parent class method/other_library.hpp +10 -0
@@ 0,0 1,10 @@
#pragma once

#include "library.hpp"

template <typename T>
class ChildClass : public TemplatedClass<T>
{
public:
    int method() override;
};

A content/blog/linking-by-example/exported/Resolve undefined parent class method/results/build log => content/blog/linking-by-example/exported/Resolve undefined parent class method/results/build log +8 -0
@@ 0,0 1,8 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/3] Building CXX object CMakeFiles/example.dir/other_library.cpp.o
[2/3] Building CXX object CMakeFiles/example.dir/main.cpp.o
[3/3] Linking CXX executable example

A content/blog/linking-by-example/exported/Resolve undefined parent class method/results/executable symbols => content/blog/linking-by-example/exported/Resolve undefined parent class method/results/executable symbols +46 -0
@@ 0,0 1,46 @@
$ nm --demangle ./build/example
0000000000004030 B __bss_start
                 w __cxa_finalize@GLIBC_2.2.5
0000000000004018 D __data_start
0000000000004018 W data_start
0000000000004020 D __dso_handle
0000000000004028 V DW.ref.__gxx_personality_v0
0000000000003db0 d _DYNAMIC
0000000000004030 D _edata
0000000000004038 B _end
00000000000012ec T _fini
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002034 r __GNU_EH_FRAME_HDR
                 U __gxx_personality_v0@CXXABI_1.3
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U __libc_start_main@GLIBC_2.34
0000000000001215 T main
                 U __stack_chk_fail@GLIBC_2.4
0000000000001060 T _start
0000000000004030 D __TMC_END__
                 U _Unwind_Resume@GCC_3.0
                 U operator delete(void*, unsigned long)@CXXABI_1.3.9
000000000000115a W ChildClass<int>::method()
00000000000012c2 W ChildClass<int>::ChildClass()
00000000000012c2 W ChildClass<int>::ChildClass()
00000000000011da W ChildClass<int>::~ChildClass()
00000000000011b0 W ChildClass<int>::~ChildClass()
00000000000011b0 W ChildClass<int>::~ChildClass()
0000000000001206 W TemplatedClass<int>::method()
00000000000012a8 W TemplatedClass<int>::TemplatedClass()
00000000000012a8 W TemplatedClass<int>::TemplatedClass()
0000000000001184 W TemplatedClass<int>::~TemplatedClass()
000000000000116a W TemplatedClass<int>::~TemplatedClass()
000000000000116a W TemplatedClass<int>::~TemplatedClass()
0000000000003d88 V typeinfo for ChildClass<int>
0000000000003da0 V typeinfo for TemplatedClass<int>
0000000000002010 V typeinfo name for ChildClass<int>
0000000000002020 V typeinfo name for TemplatedClass<int>
0000000000003d38 V vtable for ChildClass<int>
0000000000003d60 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info@CXXABI_1.3
                 U vtable for __cxxabiv1::__si_class_type_info@CXXABI_1.3

A content/blog/linking-by-example/exported/Resolve undefined parent class method/results/exit code => content/blog/linking-by-example/exported/Resolve undefined parent class method/results/exit code +1 -0
@@ 0,0 1,1 @@
1

A content/blog/linking-by-example/exported/Resolve undefined parent class method/results/library.cpp.o symbols => content/blog/linking-by-example/exported/Resolve undefined parent class method/results/library.cpp.o symbols +1 -0
@@ 0,0 1,1 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o

A content/blog/linking-by-example/exported/Resolve undefined parent class method/results/main.cpp.o symbols => content/blog/linking-by-example/exported/Resolve undefined parent class method/results/main.cpp.o symbols +31 -0
@@ 0,0 1,31 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
0000000000000000 V DW.ref.__gxx_personality_v0
                 U __gxx_personality_v0
0000000000000000 T main
                 U __stack_chk_fail
                 U _Unwind_Resume
                 U operator delete(void*, unsigned long)
                 U ChildClass<int>::method()
0000000000000000 W ChildClass<int>::ChildClass()
0000000000000000 W ChildClass<int>::ChildClass()
0000000000000000 n ChildClass<int>::ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
                 U TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::TemplatedClass()
0000000000000000 W TemplatedClass<int>::TemplatedClass()
0000000000000000 n TemplatedClass<int>::TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Resolve undefined parent class method/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/Resolve undefined parent class method/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Templated subclass attempt/CMakeLists.txt => content/blog/linking-by-example/exported/Templated subclass attempt/CMakeLists.txt +11 -0
@@ 0,0 1,11 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    library.cpp
    other_library.cpp
    main.cpp
)

A content/blog/linking-by-example/exported/Templated subclass attempt/commit => content/blog/linking-by-example/exported/Templated subclass attempt/commit +1 -0
@@ 0,0 1,1 @@
d6cb4e380bd2b6f753a162e0195f8d112d26a1e0

A content/blog/linking-by-example/exported/Templated subclass attempt/library.cpp => content/blog/linking-by-example/exported/Templated subclass attempt/library.cpp +4 -0
@@ 0,0 1,4 @@
#include "library.hpp"

template <typename T>
int TemplatedClass<T>::method() { return 42; }

A content/blog/linking-by-example/exported/Templated subclass attempt/library.hpp => content/blog/linking-by-example/exported/Templated subclass attempt/library.hpp +10 -0
@@ 0,0 1,10 @@
#pragma once

template <typename T>
class TemplatedClass
{
public:
    virtual ~TemplatedClass() = default;

    virtual int method();
};

A content/blog/linking-by-example/exported/Templated subclass attempt/main.cpp => content/blog/linking-by-example/exported/Templated subclass attempt/main.cpp +5 -0
@@ 0,0 1,5 @@
#include "other_library.hpp"

int main() {
    return ChildClass<int>{}.method();
}

A content/blog/linking-by-example/exported/Templated subclass attempt/other_library.cpp => content/blog/linking-by-example/exported/Templated subclass attempt/other_library.cpp +7 -0
@@ 0,0 1,7 @@
#include "other_library.hpp"

template <typename T>
int ChildClass<T>::method() { return 1; }

template class ChildClass<int>;
template class TemplatedClass<int>;

A content/blog/linking-by-example/exported/Templated subclass attempt/other_library.hpp => content/blog/linking-by-example/exported/Templated subclass attempt/other_library.hpp +10 -0
@@ 0,0 1,10 @@
#pragma once

#include "library.hpp"

template <typename T>
class ChildClass : public TemplatedClass<T>
{
public:
    int method() override;
};

A content/blog/linking-by-example/exported/Templated subclass attempt/results/build log => content/blog/linking-by-example/exported/Templated subclass attempt/results/build log +14 -0
@@ 0,0 1,14 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/4] Building CXX object CMakeFiles/example.dir/library.cpp.o
[2/4] Building CXX object CMakeFiles/example.dir/other_library.cpp.o
[3/4] Building CXX object CMakeFiles/example.dir/main.cpp.o
[4/4] Linking CXX executable example
FAILED: example 
: && /usr/bin/c++   CMakeFiles/example.dir/library.cpp.o CMakeFiles/example.dir/other_library.cpp.o CMakeFiles/example.dir/main.cpp.o -o example   && :
/usr/bin/ld: CMakeFiles/example.dir/other_library.cpp.o:(.data.rel.ro._ZTV14TemplatedClassIiE[_ZTV14TemplatedClassIiE]+0x20): undefined reference to `TemplatedClass<int>::method()'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

A content/blog/linking-by-example/exported/Templated subclass attempt/results/library.cpp.o symbols => content/blog/linking-by-example/exported/Templated subclass attempt/results/library.cpp.o symbols +1 -0
@@ 0,0 1,1 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o

A content/blog/linking-by-example/exported/Templated subclass attempt/results/main.cpp.o symbols => content/blog/linking-by-example/exported/Templated subclass attempt/results/main.cpp.o symbols +31 -0
@@ 0,0 1,31 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
0000000000000000 V DW.ref.__gxx_personality_v0
                 U __gxx_personality_v0
0000000000000000 T main
                 U __stack_chk_fail
                 U _Unwind_Resume
                 U operator delete(void*, unsigned long)
                 U ChildClass<int>::method()
0000000000000000 W ChildClass<int>::ChildClass()
0000000000000000 W ChildClass<int>::ChildClass()
0000000000000000 n ChildClass<int>::ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
                 U TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::TemplatedClass()
0000000000000000 W TemplatedClass<int>::TemplatedClass()
0000000000000000 n TemplatedClass<int>::TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Templated subclass attempt/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/Templated subclass attempt/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
                 U TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/CMakeLists.txt => content/blog/linking-by-example/exported/Workaround duplicate symbols with static/CMakeLists.txt +10 -0
@@ 0,0 1,10 @@
cmake_minimum_required(VERSION 3.27)

project(example
    LANGUAGES CXX
)

add_executable(example
    library.cpp
    main.cpp
)

A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/commit => content/blog/linking-by-example/exported/Workaround duplicate symbols with static/commit +1 -0
@@ 0,0 1,1 @@
29ebb7ab63539503bfb1f24b79974c397dd154e9

A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/library.cpp => content/blog/linking-by-example/exported/Workaround duplicate symbols with static/library.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int square_10() {
    return square(10);
}

A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/library.hpp => content/blog/linking-by-example/exported/Workaround duplicate symbols with static/library.hpp +11 -0
@@ 0,0 1,11 @@
#pragma once

extern "C" {

static int square(int num) {
    return num * num;
}

static int operand = 5;

} // extern "C"

A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/main.cpp => content/blog/linking-by-example/exported/Workaround duplicate symbols with static/main.cpp +5 -0
@@ 0,0 1,5 @@
#include "library.hpp"

int main() {
    return square(operand);
}

A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/build log => content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/build log +8 -0
@@ 0,0 1,8 @@
$ cmake -B build
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/william/scratch/public/linking-by-example/build
$ cmake --build build
[1/3] Building CXX object CMakeFiles/example.dir/library.cpp.o
[2/3] Building CXX object CMakeFiles/example.dir/main.cpp.o
[3/3] Linking CXX executable example

A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/executable symbols => content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/executable symbols +26 -0
@@ 0,0 1,26 @@
$ nm --demangle ./build/example
0000000000004018 B __bss_start
                 w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
0000000000004008 D __dso_handle
0000000000003df0 d _DYNAMIC
0000000000004018 D _edata
0000000000004020 B _end
000000000000115c T _fini
0000000000003fe8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U __libc_start_main@GLIBC_2.34
0000000000001147 T main
0000000000001119 t square
0000000000001138 t square
0000000000001020 T _start
0000000000004018 D __TMC_END__
0000000000001128 T square_10()
0000000000004010 d operand
0000000000004014 d operand

A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/exit code => content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/exit code +1 -0
@@ 0,0 1,1 @@
25

A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/library.cpp.o symbols => content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/library.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/library.cpp.o
0000000000000000 t square
000000000000000f T square_10()
0000000000000000 d operand

A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/main.cpp.o symbols => content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/main.cpp.o symbols +4 -0
@@ 0,0 1,4 @@
$ nm --demangle ./build/CMakeFiles/example.dir/main.cpp.o
000000000000000f T main
0000000000000000 t square
0000000000000000 d operand

A content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/other_library.cpp.o symbols => content/blog/linking-by-example/exported/Workaround duplicate symbols with static/results/other_library.cpp.o symbols +20 -0
@@ 0,0 1,20 @@
$ nm --demangle ./build/CMakeFiles/example.dir/other_library.cpp.o
                 U operator delete(void*, unsigned long)
0000000000000000 W ChildClass<int>::method()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 W ChildClass<int>::~ChildClass()
0000000000000000 n ChildClass<int>::~ChildClass()
0000000000000000 W TemplatedClass<int>::method()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 W TemplatedClass<int>::~TemplatedClass()
0000000000000000 n TemplatedClass<int>::~TemplatedClass()
0000000000000000 V typeinfo for ChildClass<int>
0000000000000000 V typeinfo for TemplatedClass<int>
0000000000000000 V typeinfo name for ChildClass<int>
0000000000000000 V typeinfo name for TemplatedClass<int>
0000000000000000 V vtable for ChildClass<int>
0000000000000000 V vtable for TemplatedClass<int>
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

A content/blog/linking-by-example/index.md => content/blog/linking-by-example/index.md +717 -0
@@ 0,0 1,717 @@
+++
title = "Linking in C & C++"
description = """
Do link errors haunt your dreams? Why do we need header files? Here's an
explainer for something that beginners often skip over.
"""
slug = "linking-by-example"
date = 2024-04-04

[extra]
table_of_contents = true
repo = "https://git.sr.ht/~williamvds/linking-by-example"
+++

Every C & C++ beginner's tutorial will step you through source and header files,
`.c` and `.h` respectively for C, and... well take your pick for C++: `.cpp` and
`.hpp`, `.cxx` and `.hxx`, or even `.cc` and `.hh`.

One of the build errors you'll encounter with these types of
languages is the _link error_. Something like `undefined reference to ...`. This
tends to confound developers, who roughly understand this is due to some mistake
with the compile options or build configuration.

That missing link (pardon the pun) is the linker. I'd say that's due to a common
gap in these beginner tutorials, particularly in explaining the role of the
linker. Understanding linking also explains the need for duplicating function
and class signatures in both source and header files.

So if you've found yourself confused and frustrated over these errors, read on
to master the linker once and for all.

## Building an executable

The common understanding is that the build process for a compiled language goes
something like this:

![
A graph showing several .cpp files entering a compiler, and an executable coming
out.
](simplistic-compilation.svg
"A graph showing several .cpp files entering a compiler, and an executable coming out.")

Which is true, but as explained above, for C & C++ it's missing the key step of
_linking_. The reality for a simple executable is a bit more like this:

![
](compilation-with-linking.svg
"")

The compiler doesn't produce the executables itself: it relies on the linker as
a secondary application to do so. Those `.o` files the compiler produces are
called _object files_. I'll explain what those are shortly.

There are several types of objects files. You've probably come across
at least the last one before:

- object files
  - on Unix-y platforms: `.o`
  - on Windows; sometimes `.obj`
- static libraries
  - on Unix-y platforms: `.a` for _Archive_
  - on Windows: `.lib`
- shared libraries
  - on Unix-y platforms: `.so` for _Shared Object_
  - on Windows: `.dll` for _Dynamic Link Library_

These each serve slightly different purposes. The key difference is that the
first two, object files and static libraries are _build-time dependencies_. i.e.,
once the executable has been built, they are no longer needed. You can remove
them and the executable will still run.

Shared libraries are _run-time dependencies_ of the executable. i.e., once the
executable has been built and linked to these libraries, they must (or sometimes
less strongly, _should_) be available for the executable to run correctly.

## Git repository

To dig in to how this all works, I've set up a very simple toy C++ project.

You can find it in [this
repository](https://git.sr.ht/~williamvds/linking-by-example/). I'll link to
specific commits as we go along, but for convenience, some files and diffs will
be embedded into this article.

## Objects
{{ git_commit(subject="Initial example") }}

All object files share the same purpose: they provide _symbols_. Generally,
that includes:

- functions
- data (variables, constants)
- classes (which are a combination of both data and functions)

A particularly useful tool for digging into symbols in object files is `nm`,
which is provided by [GNU binutils](https://www.gnu.org/software/binutils/).

<aside>
Note that when certain build configurations like Link-Time Optimisation (LTO)
are enabled, you'll have to use <code>nm</code> with compiler specific plugins.
GCC provides a wrapper program, <code>gcc-nm</code>.
</aside>

Here's the results of using it against a couple of object files generated from
a very simple C++ source file.

{{ embed_file(subject="Initial example", path="main.cpp", style="cpp,linenos", open=true) }}

The `extern "C"` block tells the compiler to use C's rules for linking code
within that block. I'll explain what those differences are later on. You'll
often see C or C++ headers with the following pattern:

```cpp
#ifdef __cplusplus
extern "C" {
#endif

// function declarations and such

#ifdef __cplusplus
} // extern "C"
#endif
```

The `extern "C"` is conditionally wrapped around the declarations when using a
C++ compiler, so C linking rules are always used. That's important if you're
linking a C++ application to a C library.

Let's run `nm` against the generated object file:

{{ embed_file(subject="Initial example", path="results/main.cpp.o symbols", open=true) }}


For each symbol, `nm` outputs

```
<address> <type> <symbol name>
```

**address** is the address in  ??

**type** indicates both the purpose of the symbol (e.g. function, data), and which
section it exists in the object.

**symbol name** is, unsurprisingly, the name of the symbol. Notice how for our
functions `operand` and `main`, the symbol name is simply the name of the
function.

So we've got an entry for the two functions in `main.cpp` of type `T`, and the
variable with type `d`. But what exactly do the types mean?

### Object layout and symbol types

The `nm` manual page explains the types of objects in 

    "D"
    "d" The symbol is in the initialized data section.

    ...

    "T"
    "t" The symbol is in the text (code) section.

So `T` for functions because they live in the _text_ section, and `D` for
variables because they live in the _data_ section.

As this suggests, an object file is split up into different sections for
different types of symbols. Object formats vary by platform, GNU/Linux uses
the Executable and Linking Format (ELF) from Unix System V. (!! link to some
resource) Checking the object files with `file` shows:

    $ file ./build/CMakeFiles/example.dir/main.cpp.o
    ./build/CMakeFiles/example.dir/main.cpp.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

Note ELF prefixes section names with a period, so in that context, you'll
usually see them referred to as `.text` and `.data`. The sections are just two
among many in an ELF object, but they contain most of the symbols the average
developer is interested in. Some other notable ones include:

- `.strtab`: string tables, constant strings that are embedded in the program
- `.rodata`: read-only data. When symbols in this section are loaded into a
  process' memory, that memory section is typically set to non-writable.
- `.init` and `.fini`: instructions used during a process' static init and
  destruction respectively.
- `.ctors` and `.dtors`: pointers to C++ constructor and destructor functions
  respectively.

It probably won't surprise you that read-only data contains `const` global
variables, i.e. those which exist for the lifetime of the program and are
immutable. As a quick demo, I'll make `operand` `const`:

{{ git_commit(subject="Make operand const") }}

You'll see that `operand` now has type `r`, for read-only data:

{{ embed_file(subject="Make operand const" path="results/main.cpp.o symbols" style="hl_lines=4" open=true) }}

### Executables

Use `nm` on an executable and you'll see a lot more symbols which you likely
won't recognise. Highlighted alongside these are our symbols from `main.cpp.o`:

{{ embed_file(subject="Make operand const" path="results/executable symbols" style="hl_lines=19-20 23" open=true) }}

You don't have to worry about the other symbols, they're prefixed with
underscores to indicate they're private, internal implementation details.
Most of these are internal to the GNU Compiler Collection (GCC), the compiler
suite with which this executable was compiled.

## Definitions in header files

Let's imagine `square` and `operand` are common parts of our program which will
be reused in other source files. A common pattern for C & C++ programs to share
code is using header files.

So we simply copy the definitions into a header file, right? Let's give that a
shot:

{{ git_commit(subject="Move common code into a header file") }}

{{ embed_file(subject="Move common code into a header file" path="library.hpp" style="cpp,linenos" open=true) }}

After doing so, our executable still builds and executes successfully:

{{ embed_file(subject="Move common code into a header file" path="results/build log" open=true) }}

And the symbols are identical to before:

{{ embed_file(subject="Make operand const" path="results/executable symbols") }}

So job done, right? Not quite. Let's see what happens when we add another source
file to our project.

### The One Definition Rule

{{ git_commit(subject="Add another source file") }}

This file also wants to reuse `square`, so it includes the header file which
defines the function.

{{ embed_file(subject="Add another source file" path="library.cpp" style="cpp,linenos" open=true) }}

Add this source file to the project and try compiling again, you'll hit a build
error:

{{ embed_file(subject="Add another source file" path="results/build log" open=true) }}

Now it's complaining about `multiple definition of` both our function `square`
and our variable `operand`. Notice the `ld returned 1 exit status`, indicating
that this error is actually produced by `ld`, which is GCC's linker.

So, the linker isn't happy that these symbols are defined multiple times. This
is the linker's default behaviour, because the linker doesn't know what to make
of the ambiguity.

This is called the _One Definition Rule_ (ODR) in C & C++[^odr]. C++'s rule is
slightly different, because it has additional language features which affect
linkage.

If we look into the object files you'll find that both `main.cpp.o` and
`library.cpp.o` contain the symbols `square` and `operand`:

{{ embed_file(subject="Add another source file" path="results/main.cpp.o symbols" style="hl_lines=3-4" open=true) }}
{{ embed_file(subject="Add another source file" path="results/library.cpp.o symbols" style="hl_lines=2-3" open=true) }}

So the compiler has generated the objects for each source file correctly, but
linker gives up when trying to join these two object files together into the
executable.

While in this particular case, we know that both of these symbols were generated
from the same code. In the case of `square`, we know the symbols are compatible.
But things get a bit messier with `operand`, which at this point is once again a
mutable global variable.

But what if we or some third-party code had defined its own symbols also called
`square` and `operand`? The linker has no way to determine that these and our
own versions are different and probably incompatible. So the linker gives up,
and informs you of the multiple definitions, leaving you to diagnose the issue.

Remember, `#include` is an instruction to include the full text of another file
at that line, also including any transient `#include`s in that file.
So rather than just the source file' contents that is compiled, it's the source
file's contents, plus any included files. This combination is generated by the
_preprocessor_, the part of the compiler which handles all the `#`
instructions in C & C++ code. The output of the preprocessor is called a
_translation unit_, and is then passed on to the compiler proper to generate
code.

If we visualise the preprocessor as its own separate stage, our project
currently looks like this:
![
](preprocessor.svg
"")

Those `.i` files are the translation units in between.

While you can explicitly ask the compiler to run just the preprocessing stage,
preprocessing and compilation normally occurs in a single step.

### The `static` specifier

So, each object has created its own copy of `operand` and `square`. How can we
appease the linker?

An easy workaround with C linkage is adding the `static` keyword to the
definitions.

{{ git_commit(subject="Workaround duplicate symbols with static") }}

{{ embed_file(subject="Workaround duplicate symbols with static" path="library.hpp" style="cpp,linenos" open=true) }}

Now the executable is successfully compiled:

{{ embed_file(subject="Workaround duplicate symbols with static" path="results/build log" open=true) }}

Investigating the object files again, you'll find the symbols are still
duplicated between `library.cpp.o` and `main.cpp.o`, but there's a subtle change
in `square` and `operand`: the `T` and `D` are now respectively lowercased.

{{ embed_file(subject="Workaround duplicate symbols with static" path="results/main.cpp.o symbols" style="hl_lines=3-4" open=true) }}
{{ embed_file(subject="Workaround duplicate symbols with static" path="results/library.cpp.o symbols" style="hl_lines=2 4" open=true) }}

`nm` explains the distinction thus:

> If lowercase, the symbol is usually local; if uppercase, the symbol is global (external).

A local/internal symbol in one object won't be linked across other objects.
Conversely, a global/external symbol will be linked across objects.

Also, notice that `square` and `operand` are both duplicated in the final
executable:

{{ embed_file(subject="Workaround duplicate symbols with static" path="results/executable symbols" style="hide_lines=2-18 22-24" open=true) }}

<aside>
When writing C, it's suggested to make any functions that are only used within a
single source file <code>static</code>. It's particularly important in C, because there's
only one global namespace. That means it's easy for symbol names to collide
across different translation units.
</aside>

Thinking about our particular use case - a function and variable in a header -
it's worth considering whether `static` gives you desirable behaviour.

`square` is compiled for each translation unit which includes `library.hpp`.
That can inflate build times due to the redundant compilation. It's not a big
deal with just these two symbols here, but imagine a mature codebase where lots
of code is defined as `static` functions in headers. Similarly, the duplicate
symbols can inflate the size of your executable.

Things are more complicated for `operand`, which is a mutable global. With a
copy in each translation unit, if your program depends on mutating that global,
duplicates can cause surprising behaviour.

### The `inline` specifier

An alternative to `static` is the `inline` keyword, which can serve a similar
purpose, but affects how everything is linked together at the end.

`inline` was originally intended for telling the compiler you want a function's
code to be inserted wherever it is called, avoiding the overhead of a regular
function call. In order to be inlined, a function's definition must be available
in every translation unit that calls the function, so definitions are stored in
headers. To prevent this causing duplicate symbol errors, a function defined
with `inline` has different link rules.

<aside>
Modern compilers often ignore the <code>inline</code> qualifier when generating
code, instead deciding for itself when a function should be inlined. Naturally,
higher optimisation levels introduce more inlining of code. Consequently, in
modern C & C++ code, <code>inline</code> is often used for its linkage
properties rather than code generation properties.
</aside>


{{ git_commit(subject="Make header symbols inline") }}

{{ embed_file(subject="Make header symbols inline" path="library.hpp" style="cpp,linenos" open=true) }}

{{ embed_file(subject="Make header symbols inline" path="results/main.cpp.o symbols" style="hl_lines=3-4" open=true) }}
{{ embed_file(subject="Make header symbols inline" path="results/library.cpp.o symbols" style="hl_lines=2 4" open=true) }}

{{ embed_file(subject="Make header symbols inline" path="results/executable symbols" style="hide_lines=2-18 22-24" open=true) }}

There's only one copy of the symbols in the final executable, and `square` is
now a global _weak_ symbol, while `operand` is a global _unique symbol_.

Here's the explanations from `nm`:

> "u" The  symbol  is  a unique global symbol.  This is a GNU extension to the standard set of ELF symbol bindings.  For such a symbol the dynamic linker will make sure
>    that in the entire process there is just one symbol with this name and type in use.
>
> ...
>
> "W"
> "w" The symbol is a weak symbol that has not been specifically tagged as a weak object symbol.  When a weak defined symbol is linked with a normal defined symbol, the
>    normal defined symbol is used with no error.  When a weak undefined symbol is linked and the symbol is not defined, the value of the symbol  is  determined  in  a
>    system-specific manner without error.  On some systems, uppercase indicates that a default value has been specified.

So a weak symbol is a soft dependency, and linking won't fail if it's not
present. It can also be overridden by a strong symbol with the same name.
Implicit here is that weak symbols don't collide with one another, and the
linker will pick just one definition if there are several.

<!-- ^^ TODO is there a source which states this explicitly? -->

In this case the end result is the same for both symbols: there's only one copy
in the final executable.

The general suggestion in C++ is that any functions defined in headers should be
marked `inline`, to avoid running afoul of the One-Definition Rule.
C++ has a few more options, which may be more appropriate in certain contexts.

### C++'s `constexpr` and `consteval`

Newer versions of C++ add a few extra keywords which avoid creating multiple
definitions.

`constexpr`[^constexpr], added in C++ 17, declares that a function or variable
_may_ be evaluated at compile-time.

`consteval`[^consteval], added in C++ 23, declares that a function or variable
_must_ be evaluated at compile-time.

Both of these imply `inline`, so you can use them in place of `inline` in
headers. `constexpr` and `consteval` allow the compiler to eliminate some of
your code by evaluating it at compile time, trading build time for runtime
performance.

A recommendation in C++ is to `constexpr` everything that you can. Consider
wisely what you `consteval`, because not everything needs to be evaluated at
compile-time.

There are other cases where `inline` is implicit, including:

- member function definitions that are _inside_ a class definition
- template function definitions and template variables

## Sharing definitions with other source files

Another common method for following the One Definition Rule is by moving
definitions into source files, and marking declarations with `extern`.
This keyword indicates that a symbol has external linkage, so it's the opposite
of `static`, and these specifiers are mutually exclusive. `extern` allows you
to declare symbols which are defined in other translation units, leaving the
linker to link references to those symbols later.
Note that function declarations are implicitly `extern`.

Let's make `square` and `operand` extern, and move their definitions into
`library.cpp`:

{{ git_commit(subject="Move definitions to source file") }}

{{ embed_file(subject="Move definitions to source file" path="library.hpp" style="cpp,linenos" open=true) }}
{{ embed_file(subject="Move definitions to source file" path="library.cpp" style="cpp,linenos" open=true) }}

Looking into the objects that are created, we can see a new type of symbol has
appeared in `main.cpp.o`:

{{ embed_file(subject="Move definitions to source file" path="results/main.cpp.o symbols" style="hl_lines=3-4" open=true) }}

Both `operand` and `square` are _undefined_ symbols. These are essentially
placeholders for the linker to resolve during linking. Unlike a weak symbol as
mentioned earlier, if an undefined symbol is not present during linking, the
linker raises an error. E.g., an executable which refers to an unlinked
undefined function isn't valid, because the code for that function isn't
available.

Looking at `library.cpp.o` and the final executable, `square` and `operand` are
in the regular data and text sections:

{{ embed_file(subject="Move definitions to source file" path="results/library.cpp.o symbols" style="hl_lines=2-3" open=true) }}

{{ embed_file(subject="Move definitions to source file" path="results/executable symbols" style="hide_lines=2-18 22-24" open=true) }}

This shows that the linker resolved the references to `square` and `operand` in
`main.cpp.o` to the definitions provided in `library.cpp.o`.

## C++ specific stuff

### Linkage

So, why are the link rules different between C and C++?

Because the rules for C didn't have to account for C++ features like namespaces,
overloading, and templates.

Let's take our existing example and remove the enwrapping `extern "C"` so that
the C++ link rules apply.

{{ git_commit(subject="Remove extern C") }}

{{ embed_file(subject="Remove extern C" path="library.hpp" style="cpp,linenos" open=true) }}
{{ embed_file(subject="Remove extern C" path="library.cpp" style="cpp,linenos" open=true) }}

{{ embed_file(subject="Remove extern C" path="results/library.cpp.o symbols" open=true) }}

Now the symbol names look a bit more like function declarations, because that
information is encoded in the symbol name. I say encoded, because within the
object file, C++ symbol names are _mangled_ into a different form. Since I
passed the `--demangle` option to `nm`, it has conveniently converted the names
back into a human-readable form. Without that option, things look a bit
different:

```
$ nm ./build/CMakeFiles/example.dir/library.cpp.o
0000000000000000 D operand
0000000000000000 T _Z6squarei
000000000000000f T _Z9square_10v
```

You can still roughly make out the names, but add namespaces and classes into
your files and mangled symbol names become a lot more unwieldy. You may also
notice a pattern, e.g. the `i` suffix for `square` indicates an `int` parameter,
and `v` at the end of `square_10` indicates `void` since it takes no parameters.
Mangling rules vary by compiler, so you may see a different pattern if you're
not using GCC as I am.

If you're curious, here's an example with namespaces and operator overloading:

{{ git_commit(subject="C++ overloading example") }}

And here's the compile error you get, should you try overloading with C linkage
rules:

{{ git_commit(subject="C overloading attempt") }}

### Templates

Commonly, C++ template definitions are stored in headers, and `inline` by
default. Thinking about common templates like those provided by the standard
library, e.g. `std::vector<T>`, there can be hundreds of _instantiations_ with
different types for `T` in a given program. Instantiation is when the templated
code is actually generated on-demand during compilation, with the template
arguments substituted.

Let's convert `square` to a template and see what happens:

{{ git_commit(subject="Replace with a C++ template") }}

{{ embed_file(subject="Replace with a C++ template" path="library.hpp" style="cpp,linenos" open=true) }}

{{ embed_file(subject="Replace with a C++ template" path="results/library.cpp.o symbols" style="hl_lines=3" open=true) }}

{{ embed_file(subject="Replace with a C++ template" path="results/main.cpp.o symbols" style="hl_lines=4" open=true) }}

{{ embed_file(subject="Replace with a C++ template" path="results/executable symbols" style="hide_lines=2-22" open=true) }}

Now you can see two instantiations of `square` in the final executable - one
comes from `library.cpp`, which uses `square<int>()` in `square_10()`, the other
comes from `main.cpp`, which uses `square<long>()` in `main()`.

Template instantiation occurs in specific circumstances:

> When a class template specialization is referenced in context that requires a
> complete object type, or when a function template specialization is referenced
> in context that requires a function definition to exist
[^cppref_templates]

If you analyse C++ build times with tools like
[ClangBuildAnalyzer](https://github.com/aras-p/ClangBuildAnalyzer), you'll often
find a significant amount of time is spent instantiating templated code -
particularly standard library classes, due to their popularity.

One workaround is using precompiled headers, which as the name suggests, are
headers compiled before the rest of your code. The idea is to compile frequently
used code once and reuse it, rather than generating the same code repeatedly
while compiling different translation units.

When dealing with templated classes, you can use _explicit template
initialisation_ to force the compiler to generate some templated code. It looks like this:


```c++
template <typename T>
void Function(T t) {
  // ...
}

// Instantiate Function with template argument int
template void Function<>(int);

template <typename T>
class Class {
  // ...
};

// Instantiate Class and its methods with template argument int
template class Class<int>;
```
Try to not confuse the syntax with _template specialisation_, which generally
looks like this:

```c++
template <typename T>
void Function(T t) {
  // ...
}

// Declare a specialised Function with template argument int
template <> void Function<>(int);
```

Oh the difference an empty pair of angled braces can make!

Alternatively, if you know the set of template parameters that you need up
front, you can do similar to regular functions and classes: declare them in
headers, and define them in source files. One extra step is needed: adding
template instantiations in the source file to generate the required code.

In this case we know we need square instantiation with the template parameters
`int` and `long`. So, let's move the definition for `square` into `library.cpp`,
and leave a declaration in `library.hpp`.

{{ git_commit(subject="Explicit template instantiation") }}

{{ embed_file(subject="Explicit template instantiation" path="library.hpp" style="cpp,linenos" open=true) }}
{{ embed_file(subject="Explicit template instantiation" path="library.cpp" style="cpp,linenos" open=true) }}

And looking at the object files, things look similar to the previous example
where we declared `square` in the header and defined it in the source file:

{{ embed_file(subject="Explicit template instantiation" path="results/main.cpp.o symbols" style="hl_lines=4" open=true) }}
{{ embed_file(subject="Explicit template instantiation" path="results/library.cpp.o symbols" style="hl_lines=3-4" open=true) }}

### Instantiations in multiple translation units

This all leads into my original reason for diving into this: a curious case
where we hit linking issues relating to templates.

This particular situation involved a templated class which was implemented in a
source file. We wanted to create a subclass from it, but have the subclass
reside in a different library separate to the superclass.

What this boiled down to was needing multiple instantiations in different
translation units: one for the parent class template, and one for the child
class template.

The following is a rough sketch of the code.

{{ git_commit(subject="Templated subclass attempt") }}

{{ embed_file(subject="Templated subclass attempt" path="library.hpp" style="cpp,linenos" open=true) }}
{{ embed_file(subject="Templated subclass attempt" path="library.cpp" style="cpp,linenos" open=true) }}

{{ embed_file(subject="Templated subclass attempt" path="other_library.hpp" style="cpp,linenos" open=true) }}
{{ embed_file(subject="Templated subclass attempt" path="other_library.cpp" style="cpp,linenos" open=true) }}

{{ embed_file(subject="Templated subclass attempt" path="CMakeLists.txt" style="cmake,hl_lines=9" open=true) }}

So we have a parent class defined in one source file, and a child class defined
in its own source file. The source file for the child class also explicitly
instantiates the template for both the child and parent class. Finally, I
definitely added the new source file to the project.

Despite all that, we get a missing symbol error for the parent class when
building:

{{ embed_file(subject="Templated subclass attempt" path="results/build log" open=true) }}

Looking into the object for the new source file, you'll find the root cause:

{{ embed_file(subject="Templated subclass attempt" path="results/other_library.cpp.o symbols" style="hl_lines=8" open=true) }}

There's an undefined reference to `TemplatedClass<int>::method()`, which is what
the linker is complaining about.

It's a bit confusing that we have a hard dependency on a method that is never
called, but after all, it is possible for a method override to call the parent's
version of the method. But we've explicitly instantiated `TemplateClass<int>`,
why hasn't `method()` also been instantiated? Well, it's defined in
`library.cpp`, but our explicit instantiation is in `other_library.cpp`. The
definition is inaccessible!

But how do we make the definition available without defining it in the header?

Well, how about adding `#include "library.cpp"` in `other_library.cpp`? That's
pretty much the only practical solution.

I'm convinced I've seen this pattern once before, possibly in a standard library
implementation. Typically, a different file extension is used to indicate it's
an template implementation file, e.g. `.tpp` or `.txx`. Semantically, this feels
better than `#include`ing a `.cpp` file in another.

Let's apply this here, so let's rename `library.hpp` to `library.tpp`. We can
also remove the explicit instantiation of the parent class, because that's
implicit in the instantiation of the child class.

{{ git_commit(subject="Resolve undefined parent class method") }}

{{ embed_file(subject="Resolve undefined parent class method" path="library.tpp" style="cpp,linenos" open=true) }}
{{ embed_file(subject="Resolve undefined parent class method" path="other_library.cpp" style="cpp,linenos" open=true) }}

And our link issue is resolved:

{{ embed_file(subject="Resolve undefined parent class method" path="results/build log" open=true) }}

Is this rare pattern worth introducing for a probably negligible impact on build
times? Probably not. But should you encounter this situation in the future, now
you know what to do! Hopefully you learned a thing or two along the way.

What surprises me is that there's no compiler warning when an explicit
instantiation can't generate _all_ the code required for said instantiation.
Personally I feel that's the intent behind an explicit instantiation, so the
compiler should raise if it's unable to follow that instruction. It could also
helpfully diagnose which definitions are missing. For the record, I've built
these examples with GCC 13. Maybe things will improve in later versions.

## References

[^odr]: <https://en.cppreference.com/w/cpp/language/definition>

[^constexpr]: <https://en.cppreference.com/w/cpp/language/constexpr>

[^consteval]: <https://en.cppreference.com/w/cpp/language/consteval>

[^cppref_templates]: <https://en.cppreference.com/w/cpp/language/templates>

A content/blog/linking-by-example/preprocessor.dot => content/blog/linking-by-example/preprocessor.dot +46 -0
@@ 0,0 1,46 @@
digraph branch {
  bgcolor = transparent
  color = white
  rankdir = LR

  node [fontname="sans-serif" fontsize=12 fontcolor="#eeeeee" color="#eeeeee"]
  edge [fontcolor="#eeeeee" color="#eeeeee" arrowsize=0.8]

  {
    node [shape=none margin=.1 fontname=monospace]
    "main.cpp"
    "library.cpp"
    "library.hpp"

    "main.i"
    "library.i"

    "main.cpp.o"
    "library.cpp.o"

    executable
  }

  {
    node [shape=box]

    {
      node [label="compiler"]
      compiler1
      compiler2
    }

    {
      node [label="preprocessor"]
      preprocessor1
      preprocessor2
    }

    linker
  }

  { "main.cpp", "library.hpp" } -> preprocessor1 -> "main.i" -> compiler1 -> "main.cpp.o" -> linker
  { "library.cpp", "library.hpp" } -> preprocessor2 -> "library.i" -> compiler2 -> "library.cpp.o" -> linker

  linker -> executable
}

A content/blog/linking-by-example/simplistic-compilation.dot => content/blog/linking-by-example/simplistic-compilation.dot +20 -0
@@ 0,0 1,20 @@
digraph branch {
  bgcolor = transparent
  color = white
  rankdir = LR

  node [fontname="sans-serif" fontsize=12 fontcolor="#eeeeee" color="#eeeeee"]
  edge [fontcolor="#eeeeee", color="#eeeeee", arrowsize=0.8]

  {
    node [shape=none]
    "main.cpp" -> compiler
    "source.cpp" -> compiler
    "..." -> compiler
  }

  compiler [shape=box]

  executable [shape=none]
  compiler -> executable
}

M sass/blog.sass => sass/blog.sass +6 -0
@@ 13,6 13,12 @@ article figure
		margin-bottom: variables.$space-min
		@include variables.box-shadow

article aside
	display: block
	border-left: variables.$line-width solid variables.$fg
	padding-left: variables.$space-small
	margin: variables.$space-medium 0

#toc
	ul
		list-style: none

A templates/shortcodes/embed_file.md => templates/shortcodes/embed_file.md +10 -0
@@ 0,0 1,10 @@
{% set file = "/content/" ~ page.path ~ "/exported/" ~ subject ~ "/" ~ path %}
{% set commit = load_data(path="/content/" ~ page.path ~ "/exported/" ~ subject ~ "/commit") %}
{% set code = load_data(path=file) %}
<details {% if open %}open{% endif %}>
	<summary><a href="{{page.extra.repo}}/tree/{{commit}}/{{path}}">{{file | split(pat="/") | last}}</a></summary>

```{% if style %}{{style}}{% endif %}
{{code | trim_end}}
```
</details>

A templates/shortcodes/git_commit.html => templates/shortcodes/git_commit.html +5 -0
@@ 0,0 1,5 @@
{% set commit = load_data(path="/content/" ~ page.path ~ "/exported/" ~ subject ~ "/commit") %}
<p>
See commit {{commit | truncate(length=8, end="")}} <i>{{subject}}</i>
(<a href="{{page.extra.repo}}/commit/{{commit}}">diff</a>, <a href="{{page.extra.repo}}/tree/{{commit}}">tree</a>)
</p>