Porting sl to Windows
You might have noticed that sl
is the reverse of ls
, and yes, it was created for people who mistype. Instead of a boring red message “Invalid command” or so, you can have a train running through your console with no ways to stop (Ctrl+C
is blocked). Sounds cool right? That is sl
(Steam Locomotive) by Toyoda Masashi, and you can find its source code here.
First thing that we can observe is the include file unistd.h. This is truly a POSIX header, and obviously, Windows SDK does not come with it. Commenting out does not solve problem immediately, because usleep
function depends on it. We instead implement usleep
through thrd_sleep
in threads.h (C11):
#define usleep(x) thrd_sleep(&(struct timespec){.tv_nsec=(x)*1000}, NULL)
Next, to draw on screen, the program depends on ncurses
, a library for programming TUI (terminal UI) that is based on terminfo
, which we can see through compile flag -lncurses inside Makefile. But it was not designed for Windows at all, so I replace it with PDCurses. It still interfaces through curses.h
header file so we don’t have to rename the include, which is nice. Wanting to port to CMake as well, I used vcpkg
to manage the dependency:
./vcpkg install pdcurses
and then write the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.23)
project(sl)
find_package(unofficial-pdcurses CONFIG REQUIRED)
add_executable(sl sl.c)
target_link_libraries(sl PRIVATE unofficial::pdcurses::pdcurses)
Simple, right? Now, all we have to do is executing cmake
:
cmake -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
cmake --build build --config Release -j
Note: I set $env:VCPKG_ROOT
as the path of where I installed vcpkg, but you can replace with your own absolute path.
And voila! We got sl
running on Windows.
Bonus
If you are using MSVC cl.exe
, then you might need to specify the C version, because the default C compiler of MSVC implements ANSI C89 at the time of writing. It also applies if you use old version of GCC and Clang. Below is how you do it nicely in CMakeLists.txt:
set(CMAKE_C_STANDARD 11)