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.
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 gitFedora
sudo dnf install make gitArch Linux, Manjaro, CachyOS
sudo pacman -S make gitThe 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 gitmacOS
brew install make gitNote that GNU Make is named gmake instead of make. Adjust the commands in the guide accordingly.
Start by creating a new directory for your project and initializing a Git repository:
mkdir my-cool-project
cd my-cool-project
git initCreate 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 srcCreate 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 allYou can also delete the build artifacts with the following command:
make cleanNote
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"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
┗━ .gitignoreC_SOURCES should be defined in your Makefile as follows:
C_SOURCES := main.c io.c algorithm/math.cTo 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;
}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.