Setting up a project - ylab-nsu/cdm16-llvm-neo GitHub Wiki

In this guide, you will learn how to set up a new CDM-16 project following good practices.

Prerequisites

This guide assumes that you have the CDM-16 LLVM toolchain installed and available in PATH. If not, see Getting started.

The project will use GNU Make for building and Git for version control. Ensure these programs are installed. Here are package manager commands for various common OS distributions:

Debian 12+, Ubuntu 22.04+, Linux Mint, Pop!_OS
sudo apt-get update
sudo apt-get install make git
Fedora
sudo dnf install make git
Arch Linux, Manjaro, CachyOS
sudo pacman -S make git

The command above may fail due to outdated repositories. In this case, use this command to also perform a full system upgrade:

sudo pacman -Syu make git
macOS
brew install make git

Note that GNU Make is named gmake instead of make. Adjust the commands in the guide accordingly.

Basic setup

Start by creating a new directory for your project and initializing a Git repository:

mkdir my-cool-project
cd my-cool-project
git init

Create a file called .gitignore and add build/ to it. The build directory that will contain intermediate build files and the final image:

build/

Create a subdirectory called src. It will contain your project's source code:

mkdir src

Create a C source file at src/main.c. It will contain your application's entry point:

int main(void) {
    return 0;
}

Create a file named Makefile in the project root. It will contain the build instructions for your project. Depending on the target you are using, the contents of this file will be slightly different. The ELF version has an extra build step that converts the ELF binary to a Logisim image. See LLVM targets.

Makefile for Cocas target

SRC_DIR := ./src
BUILD_DIR := ./build
IMAGE_NAME := my-cool-project.img

CC := clang-cdm
CFLAGS := -ffreestanding -O2 -MMD -MP -I$(SRC_DIR)
TARGET_ARCH := --target=cdm-cocas
ASFLAGS :=
LDFLAGS :=

C_SOURCES := main.c
ASM_SOURCES :=

C_OBJECTS := $(C_SOURCES:%=$(BUILD_DIR)/obj/%.obj)
C_DEPS := $(C_SOURCES:%=$(BUILD_DIR)/obj/%.d)
ASM_OBJECTS := $(ASM_SOURCES:%=$(BUILD_DIR)/obj/%.obj)
TARGET_IMAGE := $(BUILD_DIR)/$(IMAGE_NAME)

.PHONY: all
all: $(TARGET_IMAGE)

$(TARGET_IMAGE): $(C_OBJECTS) $(ASM_OBJECTS)
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_ARCH) -o $@ $^

$(C_OBJECTS): $(BUILD_DIR)/obj/%.obj: src/%
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) $(TARGET_ARCH) -c -o $@ $<

$(ASM_OBJECTS): $(BUILD_DIR)/obj/%.obj: src/%
	@mkdir -p $(dir $@)
	$(CC) $(ASFLAGS) $(TARGET_ARCH) -c -o $@ $<

.PHONY: clean
clean:
	rm -rf $(BUILD_DIR)

-include $(C_DEPS)
Makefile for ELF target

SRC_DIR := ./src
BUILD_DIR := ./build
IMAGE_NAME := my-cool-project.img

CC := clang-cdm
OBJCOPY := llvm-objcopy-cdm
CFLAGS := -ffreestanding -O2 -MMD -MP -I$(SRC_DIR)
TARGET_ARCH := --target=cdm
ASFLAGS :=
LDFLAGS :=

C_SOURCES := main.c
ASM_SOURCES :=
LD_SCRIPTS :=

C_OBJECTS := $(C_SOURCES:%=$(BUILD_DIR)/obj/%.o)
C_DEPS := $(C_SOURCES:%=$(BUILD_DIR)/obj/%.d)
ASM_OBJECTS := $(ASM_SOURCES:%=$(BUILD_DIR)/obj/%.o)
TARGET_IMAGE := $(BUILD_DIR)/$(IMAGE_NAME)
TARGET_BINARY := $(basename $(TARGET_IMAGE)).elf

.PHONY: all
all: $(TARGET_IMAGE)

$(TARGET_IMAGE): $(TARGET_BINARY)
	@mkdir -p $(dir $@)
	$(OBJCOPY) -O logisim $< $@

$(TARGET_BINARY): $(C_OBJECTS) $(ASM_OBJECTS) $(LD_SCRIPTS)
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_ARCH) -o $@ $^

$(C_OBJECTS): $(BUILD_DIR)/obj/%.o: src/%
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) $(TARGET_ARCH) -c -o $@ $<

$(ASM_OBJECTS): $(BUILD_DIR)/obj/%.o: src/%
	@mkdir -p $(dir $@)
	$(CC) $(ASFLAGS) $(TARGET_ARCH) -c -o $@ $<

.PHONY: clean
clean:
	rm -rf $(BUILD_DIR)

-include $(C_DEPS)

You can now build your project with GNU Make. The output Logisim image will be placed at build/my-cool-project.img

make all

You can also delete the build artifacts with the following command:

make clean

Note

Writing Makefiles is a fairly broad topic and is not covered in these guides. To understand how to write Makefiles by yourself, check out Makefile Tutorial by Example.

When you're done setting up the project, create a Git commit:

git add .
git commit -m "Add project boilerplate"

Adding more files

You can create more C source code files in src and add them to your project by appending their names to C_SOURCES in the Makefile. The names are separated by spaces. If a source file is in a subdirectory, use its path relative to src.

Every source file (except the entry point) typically has a corresponding header file containing public function declarations and macro definitions. Place these header files alongside their source code counterparts. You do not need to register them in the Makefile.

For example, if your project looks like this:

my-cool-project
┣━ src
┃  ┣━ algorithm
┃  ┃  ┣━ math.h
┃  ┃  ┗━ math.c
┃  ┣━ main.c
┃  ┣━ io.h
┃  ┗━ io.c
┣━ Makefile
┗━ .gitignore

C_SOURCES should be defined in your Makefile as follows:

C_SOURCES := main.c io.c algorithm/math.c

To use a function defined in a different source file:

  • add a declaration to the corresponding header file
  • include the header in the file where you want to use the function

For example:

// algorithm/math.c
void my_complex_algorithm(void) {
    // This is the function you want to use in main.c
}
// algorithm/math.h
void my_complex_algorithm(void);
// main.c
#include "algorithm/math.h"

int main(void) {
    my_complex_algorithm();
    return 0;
}

Visual Studio Code tasks

If you are using VSCode, and you want to use the IDE task functionality (i.e. build the project with Ctrl+Shift+B), create a file named .vscode/tasks.json with the following contents:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build Project",
            "type": "shell",
            "command": "make",
            "args": [ "all" ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": []
        },
        {
            "label": "Clean Project",
            "type": "shell",
            "command": "make",
            "args": [ "clean" ],
            "group": {
                "kind": "build"
            },
            "problemMatcher": []
        }
    ]
}

Note

If you are using VSCode on macOS, change the value of command from make to gmake.

This file should be kept in Git.

⚠️ **GitHub.com Fallback** ⚠️