22 KiB
Build system
Building an operating system is tricky: there are many different components to be built that all support varying configurations, and there are lots of dependencies (including compilers and assemblers) that need to be prepared. The Essence build system has been designed to make this as much of a streamlined process as is possible. And hopefully it is a lot easier than building other operating systems from scratch (for a comparison, see the wonderful "Linux From Scratch" books).
The build system is divided into three components: util/start.script
, util/build.c
and util/build_core.c
("build core").
util/start.script
first verifies the environment is acceptable for building Essence. It then compilesutil/build.c
. It then enters a command prompt interface where the developer can issue commands to build and test project, and additionally manage configurations, emulators, ports and the source tree. Most commands are implemented by calling out toutil/build.c
.util/build.c
implements most of the high-level operations of commands called inutil/start.sh
. However, its functionality is being slowly moved intoutil/start.script
, so that it can be removed.- Build core is responsible for actually building Essence components, and producing a finished drive image. It expects all dependencies and the toolchain to be prepared before it is executed. It is able to run within Essence itself (where dependencies and a toolchain are already provided). It has minimal interaction with the platform it is running on. It is typically invoked automatically by
util/build.c
, which passes a description of the requested build inbin/build.ini
. This includes information of the toolchain to use, enabled options, applications and drivers to compile, fonts to bundle, installation settings (such as how large the drive image should be), and other general settings (like how many threads to compile with, and whether optimisations are enabled).
util/build_common.h
contains common definitions shared between these components.
util/build.c
The following commands are available in the interactive prompt:
help
Print a list of the most commonly used commands, with a short description.exit
,x
,quit
,q
Exit the interactive prompt.compile
,c
Compile the operating system components with optimisations disabled. This does not produce a drive image.build
,b
Build the operating system tobin/drive
with optimisations disabled.build-optimised
,opt
Build the operating system tobin/drive
with optimisations enabled.debug
,d
Build the operating system tobin/drive
with optimisations disabled, and then launch Qemu configured to wait for GDB to attach to it before starting.vbox
,v
Build the operating system tobin/vbox.vdi
with optimisations enabled, and then launch VBox. To use this, you need to make a 128MB drive calledvbox.vdi
in thebin
folder, and attach it to a virtual machine called "Essence" (choose "Windows 7 64-bit" as the OS).vbox-without-opt
,v2
Same asv
but with optimisations disabled.vbox-without-compile
,v3
Same asv
but compilation is skipped.qemu-with-opt
,t
Build the operating system tobin/drive
with optimisations enabled, and then launch Qemu.test
,t2
Same ast
but with optimisations disabled.qemu-without-compile
,t3
Same ast
but compilation is skipped.qemu-with-kvm
,k
Same ast
but Qemu is launched with the-enable-kvm
flag. This results in significantly faster emulation. The command also disables theFlag.DEBUG_BUILD
option; see below for a description of this.build-cross
Force a rebuild of the cross compiler toolchain.build-utilities
,u
Build the utility applications only, which will run on the host development system. This is done automatically as needed by the other commands.make-installer-archive
Compress the contents ofroot/
to make a archive for use by the system installer application. This outputs the filesbin/installer_archive.dat
andbin/installer_metadata.dat
.make-installer-root
Copy all the needed files to make an installer image toroot/
. You need to runmake-installer-archive
first.font-editor
Compile and launch the bitmap font editor utility application. This requires X11.config
Compile and launch the config editor utility application. This requires X11.designer2
Compile and launch the theme editor utility application. This requires X11.replace-many
Replace a list of strings in the source code. A file containing the strings to replace and their replacements is passed. Each line should be of the form<thing to replace> <what to replace it with>
.replace
Replace a string in the source code. Only full words are matched.replace-in
Same asreplace
, except it only replaces in a single folder.find
Find a string in the source code. Ignores binary files.find-word
Same asfind
, except only the full word is matched. For example,at
would not matchcat
.find-in
Same asfind
, except it looks in a single folder.fix-replaced-field-name
After renaming a structure field, run this to change all references to it. It parses the compiler errors to do this automatically.ascii <string>
Converts a string to ASCII codepoints.build-optional-ports
Runs theport.sh
script in each of the folders inports/
. If there is no script, the folder is skipped. Note that to use many of the ports the POSIX subsystem must be enabled.do <string>
Run a command throughsystem()
.live
Build a live CD or USB image. Work in progress.line-count
Calculate the number of lines of code in the project.a2l <symbols file>
Run the a2l utility. See the "a2l" section.build-port
Build a single port. A list of availble ports are listed.get-source <folder name> <url>
The file at the URL is downloaded and cached inbin/cache
. The download is skipped if the file was already cached. It is then extracted and untar'd. The folder of the given name is then moved tobin/source
.get-source-checked <sha256> <folder name> <url>
Same asget-source
except the downloaded file has its SHA-256 checksum compared against the given value.make-crash-report
Copies various system files and logs into a.tar.gz
which can be used to report a crash.setup-pre-built-toolchain
Setup the pre-built toolchain for use by the build system. You can download and prepare it by running./start.sh get-source prefix https://github.com/nakst/build-gcc/releases/download/gcc-11.1.0/gcc-x86_64-essence.tar.xz
followed by./start.sh setup-pre-built-toolchain
.run-tests
Run the API tests.desktop/api_tests.ini
must be added tobin/extra_applications.ini
, andEmulator.SerialToFile
must be enabled.
Levels of optimisation
Commands in the build system provide two levels of optimisation, either with optimisations enabled or disabled. However, there is an additional configuration flag, Flag.DEBUG_BUILD
which can be toggled in the configuration editor. This determines whether the DEBUG_BUILD
flag will be defined in the source code or not. When this flag is defined, many expensive checks are performed to constantly validate the operating system's data structures. To make a "fully optimised" build of Essence, you should first disable this flag, and then build with optimisations enabled.
Note that some commands will force disable the Flag.DEBUG_BUILD
option. Most notably, the k
command.
Build core
Build core can run in three modes. The mode is passed as the first argument.
headers <language> <path-to-output-file>
Generates the API header forc
(also works for C++),odin
orzig
, and saves it to the provided output path.application <configuration>
Builds a single application, given its configuration file. This will not install the application. See the "Application configuration options" section below.standard <configuration>
Builds the system, given the configuration file. See the "Standard build configuration options" section below.
Application configuration options
In the [build]
section:
source
Path to the source file. This can be repeated, if the application has multiple translation units.compile_flags
Additional flags to be passed to the compiler.link_flags
Additional flags to be passed to the linker.with_cstdlib
Set to 1 to link to the C standard library (currently Musl). This requires enabling the POSIX subsystem. Defaults to 0.require
Optional. Set to the path of a file that must exist for the application to be built. If the file is not found, then the application will not be built.custom_compile_command
A custom build command for the application. If this is set, then the default calls to the compiler and linker will be skipped. This command will be passed directly tosystem()
. It should output an ELF executable tobin/<application name>
. The application name is taken from the[general]
section.
In the [general]
section:
name
The name of the application.disabled
Set to 1, and the application will not be built.needs_native_toolchain
Set to 1 if the application requires a native toolchain to build. TODO Merge this withwith_cstdlib
from[build]
?icon
The name of the icon fromdesktop/icons.header
to use for the application. This method of setting the application's icon should only be used for builtin application; third party application can set the icon of their application in the[embed]
section. See below.use_single_process
Set to 1 if the application should use a single process, shared between all its instances. Default is 0.use_single_instance
Set to 1 if the application can only have a single instance open at a time. If the application is already open and the user tries to open it again, then the tab containing the loaded instance will be switched to. Default is 0.hidden
Set to 1 if the application should not be listed on the "New Tab" screen.permission_<permission>
Set to 1 to grant the application a specific application permission.is_file_manager
Set to 1 if the application is the file manager. For system use only!is_installer
Set to 1 if the application is the installer. For system use only!background_service
Set to 1 if the application should be loaded at startup as a background service. For system use only!
In the [embed]
section there is a list of files that should be embedded into the application bundle. These embedded file can be accessed at runtime using the EsBundleFind
API. The entries in this section are of the form <embedded name>=<path>
. Embedded name prefixed with $
are reserved for definition by the system. The ELF executable files are automatically embedded into the application's bundle, with names of the form $Executables/<target>
. The application's icon should be embedded as PNG images with names of the form $Icons/<size>
. You must, as a minimum, provide sizes 16
(16x16 pixels) and 32
(32x32 pixels).
Each [file_type]
section provides information about a file type.
match
Gives the file name extensions to match for the file type.name
Gives the readable name of the file type, which will be shown to the user. TODO Translations.icon
Gives the name of the icon fromdesktop/icons.header
to show for files of this type. TODO Bundled icons.has_thumbnail_generator
Set to 1 if the file type has a thumbnail generator. Only images are supported at the moment. TODO Custom thumbnail generators.uuid
The EsUniqueIdentifier of the file type.textual
Set to 1 if the file type can be read by plain text editors.actions
The actions the application supports with this file type, e.g.open
.
Standard build configuration options
In the [toolchain]
section:
path
Path to thebin
folder of the toolchain.tmpdir
A path to use to store temporary files. Passed to the toolchain in theTMPDIR
environment variable.ar
,cc
,cxx
,ld
,nm
,strip
,nasm
,convert_svg
Paths to the toolchain executables.linker_scripts
Path to the linker scripts. This should be set to theutil/
folder of the source tree.compiler_objects
The path containing thecrt*.o
files provided by the toolchain.crt_objects
The path wherecrt*.o
files will be output.
In the [general]
section:
system_build
Set to 1 to build the bootloader, Desktop and Kernel.minimal_rebuild
Set to 1 to enable minimal rebuilds. Dependency information is stored inbin/dependencies.ini
. Only components where the dependent source files have been modified will be rebuilt. All components are rebuilt if any of the options in this configuration file are modified.colored_output
Set to 1 to enable ANSI color codes in the output.thread_count
Set to the number of threads to use for calling the toolchain.target
Set the name of the target platform, e.g.x86_64
.skip_header_generation
Set to 1 if the C/C++ API header does not need to be regenerated.verbose
Set to 1 to list every toolchain invocation. Seethread_count=1
if you are using this.common_compile_flags
Additional flags to pass to the C/C++ compiler invocations for all components.for_emulator
Set to 1 to enable a few features that improve the experience of running the system on an emulator.optimise
Enable compiler optimisations.skip_compile
Skip compiling components and only build a drive image from the previously built executables.
In the [install]
section:
file
The output file to put the drive image in.partition_size
The size of the drive image in megabytes.partition_label
The label of the partition. This can be set to anything you like, as long as it doesn't exceedESFS_MAXIMUM_VOLUME_NAME_LENGTH
.
In the [options]
section there is a copy of the options in "Configuration options", from bin/config.ini
. Note that many of these options are not handled by build core, but rather by util/build.c
. See the "Configuration options" section for more details.
Each [application]
section should contain a single key, manifest
, giving the path to the application configuration options (see the above section).
Each [driver]
section should contain:
name
The name of the driver. This must be found inkernel/config.ini
.source
The source file of the driver. This must be C/C++.builtin
Set to 1 if the driver should be linked directly into the kernel. Set to 0 if the driver should be built as a loadable module.
[font]
sections specify the fonts that are to be bundled in the desktop executable. Each section should contain:
name
The name of the font.category
One ofSans
,Serif
orMono
. More categories will likely be added in the future.scripts
The scripts supported by the font. Seehb_script_t
inbin/harfbuzz/src/hb-common.h
for a list of scripts. Separate each script with a,
.license
The license file to bundle. This is a path relative tores/Fonts/
..<digit>
and.<digit>i
The font file for a weight 1-9, withi
for italics. More possibilities will likely be added in the future. This is a path relative tores/Fonts/
.
Configuration editor
You can start the configuration editor by typing config
at the build system prompt. Click Save
to save your changes. Click Defaults
to load the defaults. Left click an option in the table to toggle it or otherwise modify it. You will be presented with a warning if modifying the option is not recommended. Right click to reset a specific option. The changes are saved to bin/config.ini
, which will not be uploaded to source control.
See the section "Configuration options" for a description of what each option does.
Configuration options
Options starting with Driver.
are used to enable and disable drivers. The defaults will be configured to work optimally for development work in emulators.
Emulator options
Emulator.AHCI
Use AHCI/SATA for the drive in Qemu.Emulator.ATA
Use ATA/IDE for the drive in Qemu.Emulator.NVMe
Use NVMe for the drive in Qemu.Emulator.CDROMImage
A path to a CD-ROM image that will be passed to Qemu.Emulator.USBImage
A path to a drive image that will be passed to Qemu to appear as a USB mass storage device.Emulator.USBHostVendor
,Emulator.USBHostProduct
The vendor and product of a USB device to pass-through to Qemu. You will probably need to setEmulator.RunWithSudo
for this to work.Emulator.RunWithSudo
Run Qemu withsudo
.Emulator.Audio
Enable audio output in Qemu, saved tobin/audio.wav
.Emulator.MemoryMB
The amount of memory for Qemu. Probably needs to be at least 32 MB.Emulator.Cores
The number of CPU cores to use in the emulator. Use 1 for a better debugging experience. Note that the build system command "k" automatically uses the maximum number of CPU cores possible.Emulator.PrimaryDriveMB
The size of the primary drive image.Emulator.SecondaryDriveMB
The size of a secondary drive image that will be connected to the emulator.Emulator.VBoxEFI
Use UEFI boot in VBox.Emulator.QemuEFI
Use Qemu boot in VBox.Emulator.SerialToFile
Save the serial output from Qemu tobin/Logs/qemu_serial1.txt
. If disabled, then the output will be available as a separate display in Qemu, but will not be saved after Qemu exits! You can view the serial output saved to a file as it is output using the shell commandtail -f bin/Logs/qemu_serial1.txt
.
Build core options
BuildCore.Verbose
Set to enableverbose
flag passed to build core. See the[general]
section of the build core options.BuildCore.NoImportPOSIX
Do not import theroot/Applications/POSIX
folder onto the drive image. This will allow building much smaller drive images.BuildCore.RequiredFontsOnly
Only import the minimal number of fonts onto the drive image. This will allow building much smaller drive images.
Flag options
Flag.ENABLE_POSIX_SUBSYSTEM
Enable the POSIX subsystem. Needed to use most ports and the POSIX Launcher.Flag.DEBUG_BUILD
Set to 1 to define theDEBUG_BUILD
flag. See the "Levels of optimisation" section above.Flag.USE_SMP
Enable symmetric multiprocessing. You may wish to disable this for easier debugging.Flag.PROFILE_DESKTOP_FUNCTIONS
Set to 1 to enable gf profiling integration for the Desktop.Flag.BGA_RESOLUTION_WIDTH
The default resolution width to use for BGA, the graphics adapter used by Qemu. Must be a multiple of 4.Flag.BGA_RESOLUTION_HEIGHT
The default resolution height to use for BGA, the graphics adapter used by Qemu. Must be a multiple of 4.Flag.VGA_TEXT_MODE
Use VGA text mode at startup. Use withFlag.START_DEBUG_OUTPUT
for early debugging.Flag.CHECK_FOR_NOT_RESPONDING
Set to enable the Desktop's feature of checking whether the foreground application is responding. Disabling this will reduce the number of thread switches, making debugging slightly easier.Flag._ALWAYS_USE_VBE
Use VBE mode setting. Needed for real hardware, if using the MBR bootloader.Flag.COM_OUTPUT
Set to enable serial output. Should be disabled before making a build to run on real hardware.Flag.POST_PANIC_DEBUGGING
Set to enable the special debugger that runs after aKernelPanic
. Requires a PS/2 keyboard.Flag.START_DEBUG_OUTPUT
Log kernel messages to the screen immediately during startup.Flag.PAUSE_ON_USERLAND_CRASH
Send a userland application into a spin loop when it crashes. This makes it possible to attach a debugger (seeDebugging.md
) and get a stack trace.
General options
General.first_application
The name of application to launch at startup. Useful if you don't want to have to manually open it from the "New Tab" page every time you restart the emulator.General.wallpaper
The path to the wallpaper file. This is an Essence path; paths beginning with0:/
will correspond to the files in theroot/
folder of the source tree.General.window_color
The default window color.General.installation_state
The installation state. If set to1
, then the installer will be invoked.make-installer-root
should have been run before doing this.General.ui_scale
The default UI scale, as a percentage.General.keyboard_layout
The default keyboard layout. SeeBuilding.md
for instructions on how to set this.
Dependency options
You can disable optional dependencies using these options.
Dependency.ACPICA
ACPICA is a kernel driver that provides power management through ACPI. Without it, the system will not be able to turn off the computer or provide thermal management.Dependency.stb_image
stb_image provides loading images of various formats. Without it, the system will only be able to load PNG images.Dependency.stb_image_write
stb_image_write provides writing images of various formats. Without it, the system will not be able to save images. Note that theImage Editor
application includes this library regardless of this setting.Dependency.stb_sprintf
stb_sprintf provides the printf-like API calls. Without it, these calls will be redirected toEsUnimplemented
. Other optional dependencies may require this to be enabled.Dependency.FreeTypeAndHarfBuzz
FreeType and HarfBuzz provide support for TrueType font rendering. Without it, the system will only be able to load bitmap fonts.
Additionally, there is the MD4C library which is included by the Markdown Viewer
application.
a2l
This utility is used to convert hexadecimal code addresses into line numbers. Start it with ./start.sh a2l <path to symbol file>
. Recall that symbol files are saved to bin/<application name>
. Paste in any text containing addresses and they will be converted to line numbers, if possible. Usually you will want to do this for the crash information logged in bin/Logs/qemu_serial1.txt
.