C and C++ is known for its abysmal dependency and build system situation. For
historic reasons a build system has not been standardized thus low level build
tools such as make
and ninja
as well high-level build tool generators such
as Autotools, CMake, meson and entire build frameworks like bazel have come and
gone throughout the years.
A lesser known build generator is
coremake. And lets be honest: it is a
horrible, underdocumented piece of shit written in hard-to-follow spaghetti C. I
would not even call it a build system generator it is more a static generator
tool that reads its own undocumented domain-specific language (which is actually
not that bad because like meson it can only declare dependencies) written in
.proj
files and a so-called “platform” file that, amusingly, ends in .build
.
That platform file is does not just specify a certain tool
chain and maybe CFLAGS
but is a hodge podge of that and instructions how to
generate output. As you can tell from the official repo, insane people have done the
insane and written generator code for Android, make
, Visual Studio and
whatnot.
Since, the make
backend defaults to recursive Makefile
s (booo), I was
tempted to add one more to the whatnots and that is
ninja. Some may know it as the default backend of
meson and an optional backend of CMake. Anyhow, on a
scale of 1 (make) to 10 (bazel) in terms of stuff, it ranges somewhere between
0.01 and 0.02 thus all logic must come from a meta build system. And to spare
you the work of figuring this out, here is something for the second
advent which allows you doing this
$ coremake ninja-clang-linux_86_64
$ ninja
$ ninja -t compdb > compile_commands.json
Adding basic ninja support to coremake was a small adventure. Although ninja’s
description language is super easy to follow, figuring out coremake’s quirks
concerning scoping and path makes you want to puke and I am certain I have only
scratched 5% of the disgusting surface.
Canon shipped their newest and cheapest full frame camera, the Canon EOS RP, end
of February. In their infinite wisdom, they decided that they had to to
develop a new CR3 format for this as well as the previously released EOS R and
M50 cameras. And of course, so far no one was able to reverse-engineer the raw
format entirely, so it
will take a good while until those cameras will be supported by all major open
source raw programs out of the box. The last option is running the Adobe DNG
Converter in a Windows VM or under Wine to convert the proprietary CR3 format
into their (intermediate) DNG format. After a good month, Adobe released a new
version that
supported the RP … but it stopped working under Wine 🤦. So, whoever stumbles
upon
Unhandled exception: unimplemented function api-ms-win-core-winrt-error-l1-.GetRestrictedErrorInfo called in 64-bit code
open winecfg
, go to Libraries, add two entries for
api-ms-win-core-winrt-error-l1-1-0
and deactivate them. The DNG converter will
complain but it will work (much faster than in a Windows 10 VM!) nevertheless.
Whoever is reading this blog knows that I use
Ledger-likes to track my
finances. Some of you may also know that the currency is just some arbitrary
name for any kind of unit. And a minority of you may also know there is special
support for tracking time in the original Ledger program. This post explains
how I use Ledger and a few Bash aliases to track different activities during a
normal work day.
In a “regular” Ledger file you will find transactions that describe the flow
of a commodity from one (or more) to another account at a certain time.
There is however special support for timelog entries in the ledger program.
They look similar but have special syntax to describe the start and end of a
“transaction”
i 2019/03/02 00:30:20 Entertainment:Netflix
o 2019/03/02 00:35:20
which basically state what to account from i
to o
. Suppose you have a
timelog file foo.ledger
then ledger -f time.ledger bal
would give you
something like this:
9.07h Work
32.3m Mail
6.9m Admin
8.40h Development
1.69h Entertainment:Netflix
14.2m Drinking
11.9m Meetings
--------------------
11.19h
Of course, you can customize the date range and hierarchy depth. Let’s alias
that to
alias wasted='ledger -f ${TIMELOG} bal -b $(date -dlast-monday +%m/%d) --depth 2'
All good. Now, adding new entries by “punching in” new lines like that above is
more than just cumbersome, it’s something a simple alias could do as well. I
have defined something like
alias clock-in='echo i $(date +"%Y/%m/%d %H:%M:%S") >> ${TIMELOG}'
alias clock-out='echo o $(date +"%Y/%m/%d %H:%M:%S") >> ${TIMELOG}'
where TIMELOG
points to the time.ledger
file. Once you type
an appropriate transaction will be made. To check what’s currently going on,
this alias might help:
alias clock-status='[[ $(tail -1 ${TIMELOG} | cut -c 1) == "i" ]] && { echo "Clocked IN to $(tail -1 ${TIMELOG} | cut -d " " -f 4)"; wasted; } || { echo "Clocked OUT"; wasted;}'
That all looks nice and dandy until you realize you don’t remember a particular
activity you want to account you current time on. If you have used any CLI
program you probably hit Tab more than twice. Wait no more, just define
function _clock_in ()
{
local cur prev
_get_comp_words_by_ref -n : cur
local words="$(cut -d ' ' -s -f 4 ${TIMELOG} | sed '/^$/d' | sort | uniq)"
COMPREPLY=($(compgen -W "${words}" -- ${cur}))
__ltrim_colon_completions "${cur}"
}
complete -F _clock_in clock-in
and you are all set to complete the timelog entry while you clock in. You could
write more elaborate logic in an appropriate scripting language but that’s an
exercise for the reader.
I wrote about meson the awesome build system before. For C-based projects
with many test executables there is nice infrastructure, however many C++
projects probably use Google Test or Catch and a single binary which
runs the entire test suite. This is all nice and dandy with Google Test if you
compile and link the test executable straight from the unit test source files.
If however you build intermediate static libraries for organizational reasons
you will quickly notice that Google Test won’t run anything at all because the
symbols from Google Test itself won’t end up in the final
binary without specifying the
--whole-archive
flag. Luckily, meson got the link_whole
parameter since
version 0.46, so instead of declaring your static test library as
test_lib = static_library('testlib',
sources: test_sources,
dependencies: [gtest_dep] + build_deps,
)
test_dep = declare_dependency(
link_with: test_lib,
dependencies: other_deps,
)
test_binary = executable('testfoo',
sources: ['main.cpp'],
dependencies: [test_dep],
)
you would change test_dep
to
test_dep = declare_dependency(
link_whole: test_lib,
dependencies: other_deps,
)
and run your tests as usual.