Build Environments

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
TylerH
Member
Member
Posts: 285
Joined: Tue Apr 13, 2010 8:00 pm
Contact:

Build Environments

Post by TylerH »

Right now I'm setting up my umpteenth rewrite of my GNU make based build environment, and I really wish there was a better way to build my kernel(used extremely loosely in this context). Basically, I've modelled my makefile after Linux 0.0.1's, and it's idea of recursively calling make for each subsystem in the kernel. At first this seems like a good idea, but it's really kludge-like when you implement it. You end up with literally every target being PHONY, which just seems wring... Does anyone have any really intuitive way of building theirs they would be willing to share? Here's my makefile to show proof of effort:

Code: Select all

include include.mk
export BASEDIR=$(realpath .)
KNAME=extrn
LIBS=
MODS=mm

.PHONY: all
all : build

# Called by Code::Blocks
.PHONY : Debug
Debug : all

.PHONY: build
build : $(BINDIR)/$(KNAME)

.PHONY: $(BINDIR)/$(KNAME) $(foreach MOD,$(MODS),$(OBJDIR)/$(MOD).o) $(foreach LIB,$(LIBS),$(OBJDIR)/$(LIB).a)
$(BINDIR)/$(KNAME) : $(foreach MOD,$(MODS),$(OBJDIR)/$(MOD).o) $(foreach LIB,$(LIBS),$(OBJDIR)/$(LIB).a)
	ld -melf_i386 -nostdlib --oformat elf32-i386 -o $@  $+

$(OBJDIR)/%.o :
	cd $(SRCDIR)/$(basename $(@F));make;

# TODO
.PHONY: clean
clean:
include.mk:

Code: Select all

# Path related variables
BINDIR=$(BASEDIR)/bin
INCDIR=$(BASEDIR)/inc
OBJDIR=$(BASEDIR)/obj
SRCDIR=$(BASEDIR)/src

# Toolchain related variables
ASM=fasm
ASMFLAGS=-m 262144 -p 10000
CC=gcc
CFLAGS=-std=c99 -c -ffreestanding $(foreach DIR,$(INCDIR),-I$(DIR)) -m32 -masm=intel -nostdinc -Wall
C++FLAGS=-c -ffreestanding -I $(INCDIR) -m32 -masm=intel -nostdinc -Wall
LDFLAGS=-melf_i386 -nostdlib --oformat elf32-i386 --warn-unresolved-symbols

#MAKEFLAGS += -rR --no-print-directory

.SUFFIXES:.asm .c .o
.asm.o :
	$(info ==== .asm($<) -> .o($@) rule)
	@$(ASM) $(ASMFLAGS) $< $@
.c.o :
	$(info ==== .c($<) -> .o($@) rule)
	@$(CC) $(CFLAGS) $< -o $@
.o:
	$(info ==== .o($+) rule)
	@ld $(LDFLAGS) $+ -o $@
.o.o :
	$(info ==== .o($+) -> .o($@) rule)
	@ld $(LDFLAGS) -r $+ -o $@
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Re: Build Environments

Post by Creature »

I've been switching back and forth between build environments as well to find the one most suitable for me. At first (back when I used Visual Studio 2008) I just set up a custom build rule that would build ald Assembly/C/C++ files appropriately and then do a post-build step for the link and making the ISO. Later I stepped over to different IDE's that used makefiles. All of this worked fine but I wasn't happy with most of the IDE's after a time so I switched to others, tried other things etc. Eventually I tried to use Notepad++ but saw that I did prefer an IDE so now I'm back to using Visual Studio 2010 as editor only (which has a really different way of handling custom build rules in comparison to older versions).

I tried making Makefiles in the past but for some reason I don't like setting one up so now I'm stuck with pretty much a tool I wrote myself. All it does at the moment is recursively check the directories you give and build the files with the given tools. It doesn't support minimal rebuild or anything (which wouldn't be easy, since GCC only seems to care for auto-generating dependency makefiles on that behalf) but my kernel isn't too big so rebuilding every source file simultaneously isn't too bad.

I'm sure others have better experiences with makefiles, but I think I just can't get used to using them.
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Re: Build Environments

Post by JamesM »

I've just moved from using Makefiles (one single Makefile, based on the same principle as Solar's Makefile tutorial) to CMake.

I've (in the past) tried Makefiles, CMake, SCons and Megamake. Megamake is terrible, don't even go there. Makefiles tend to do the job pretty well and pretty fast. They only really become a problem the more complex your project gets - my project has 40000 lines of code, unavoidable cyclical library dependencies, dependencies on LLVM, 3 flex scanners, 2 bison parsers, a suite of integration tests... you get the picture.

The dependencies just became too much for me to manage effectively with Make alone. I required configurability of needed libraries and executables too, so I now use CMake which generates makefiles - so it goes just as fast as Make does.

SCons I've found to be *horrendously* slow. YMMV.

Try some different systems, see which one you like best. For reference, and because it's a decent makefile, my Makefile is here. It's a single-file Makefile (no recursive make!) so the -j option actually works... ;)

Cheers,

James
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Build Environments

Post by gerryg400 »

TylerAnon, I'm using a system similar to yours and it works quite well. I have a Makefile in every directory and a default.mk that is included at the end of every Makefile. It knows how to build .o files (obviously), but also knows how to build targets like LIBRARY, BINARY, and sub-directories. The only phony targets are SUBDIRS and clean. For example my kernel Makefile looks like this

Code: Select all

BINARY = kernel

OBJECTS = \
	k0.o \
	kglobal.o \
	kinit.o \
	kmalloc.o \
	ktrap.o \
	kentry.o \
	ksmp.o \
	ksyscall.o \
	kintr.o \
	ktimer.o \
	kthread.o \
	ksched.o \
	kap0.o \
	kvirt.o \
	kexch.o \
	kmsg.o

CFLAGS = $(KERNEL_CFLAGS)
LDFLAGS = $(KERNEL_LDFLAGS) -L ../lib -l kern -L ../mm -l mm

include $(SYSROOT)/build/default.mk

.NOEXPORT:
The top level kernel Makefile looks like this

Code: Select all

SUBDIRS = loader lib mm kernel 

include $(SYSROOT)/build/default.mk

.NOEXPORT:
The default.mk handles everything including header file dependencies. The only thing I am not happy with is with the inclusion of default.mk. I with there was a way to include it without having to set the path.
If a trainstation is where trains stop, what is a workstation ?
xyzzy
Member
Member
Posts: 391
Joined: Wed Jul 25, 2007 8:45 am
Libera.chat IRC: aejsmith
Location: London, UK
Contact:

Re: Build Environments

Post by xyzzy »

Out of all the build systems I've tried, I've found SCons to be by far the best. The build scripts are written in Python, which make them incredibly easy to write. It's also highly customisable - I've got a whole bunch of custom methods in my system for building using my OSes tools, seamlessly handling library include directories, and more. For example, the build script for my UI server:

Code: Select all

Import('env')

# Generate the RPC interface code.
env.RPCServer('org.kiwi.WindowServer.cc', 'org.kiwi.WindowServer.proto')

# Build the service.
env.KiwiService('window',
	sources = [
		'org.kiwi.WindowServer.cc',
		'Compositor.cc',
		'Connection.cc',
		'Cursor.cc',
		'Decoration.cc',
		'Display.cc',
		'InputManager.cc',
		'MouseDevice.cc',
		'Session.cc',
		'Surface.cc',
		'Window.cc',
		'WindowList.cc',
		'WindowServer.cc',
	],
	libraries = ['kiwi-service', 'kiwi-ui', 'pixman', 'cairo', 'freetype'],
)
This generates RPC interface code (using a custom tool, which will be built if it has not already), builds the server with all the include directories for those libraries in the include path, and makes sure that it's added to the target system's filesystem in the right place.

With regard to what JamesM said about speed: it's certainly not the fastest thing on the planet, however I wouldn't say it's horrendously slow. It's certainly never been slow enough to annoy me, even on a slow system.
TylerH
Member
Member
Posts: 285
Joined: Tue Apr 13, 2010 8:00 pm
Contact:

Re: Build Environments

Post by TylerH »

I forgot to mention a Window's/Linux compatibility requirement. I primarily develop on my Linux laptop, but I also do a lot at my Windows-based school. Although I must admit, Windows versions of make suck pretty bad... Is there anything that has a dependable port for both OSes?

Thanks for all the recommendations. I'll check them out.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re: Build Environments

Post by Candy »

My OS makefile is the following:
http://quokforge.org/projects/atlantiso ... y/Makefile

Uses includes for additional rules needed by other targets. It derives most of the rules automatically though; the rest of the files together are about 100 lines again.


For simpler development I have a default makefile that
- builds a single target as an executable
- with all the cpp source files in or under the current directory
- with automatic dependency handling
- with everything that you could set auto-derived from the environment.

Put it in a directory called X and it will make all the cpp files into an output executable called X. No customisation necessary.

Code: Select all

CCFLAGS=-MMD -MP
CC=g++
LD=g++
TARGET=$(shell basename `pwd`)
OBJECTS=$(patsubst %.cpp,%.o,$(shell find ./ | grep cpp$))
DEPFILES=$(patsubst %.o,%.d,$(OBJECTS))
TEMPFILES=$(shell find ./ | grep \\.d$) $(shell find ./ | grep \\.o$)

$(TARGET): $(OBJECTS) Makefile
       @echo LD $@
       @$(LD) -o $@ $(filter %.o,$^)

%.o: %.cpp Makefile
       @echo CC $@
       @$(CC) $(CCFLAGS) -c -o $@ $<

clean:
       @$(RM) $(TARGET) $(TEMPFILES)

-include $(DEPFILES)
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Build Environments

Post by Combuster »

TylerAnon wrote:Windows versions of make suck pretty bad... Is there anything that has a dependable port for both OSes?
Cygwin's make works perfectly fine for me. I develop on windows most of the time, but occasionally on linux and I haven't seen any windows-specific issues.

That said, my OS has too much dependencies and different treatments that there is no 50-line solution possible with any build tool. Files that should not be included with some builds, files that do need to be included in some builds, differences between libraries and applications, tools that need to be compiled before being used in the build process itself, its all there. And still make does its job pretty well although dependency generation sucks since I'm doing that manually. No recursive make involved btw.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
xyzzy
Member
Member
Posts: 391
Joined: Wed Jul 25, 2007 8:45 am
Libera.chat IRC: aejsmith
Location: London, UK
Contact:

Re: Build Environments

Post by xyzzy »

TylerAnon wrote:I forgot to mention a Window's/Linux compatibility requirement. I primarily develop on my Linux laptop, but I also do a lot at my Windows-based school. Although I must admit, Windows versions of make suck pretty bad... Is there anything that has a dependable port for both OSes?
Last time I checked, my SCons system works fine under Cygwin on Windows.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Build Environments

Post by pcmattman »

We use SCons (at times fairly badly ;) ) for Pedigree. The biggest speed hit is a 7-second wait for the SConscript+SConstruct parse & run - once that's complete and dependencies and such have been checked build times are on par with <your build system here>. I've personally found it to be fairly easy to use when adding in new targets for compilation, including custom targets such as disk image generation.

That said, it's far too easy to do a SCons build system completely wrong and end up with horrible performance or bad dependency trees... but if you're aware of what you're doing it's great (I haven't found anything better yet!) :)
TylerH
Member
Member
Posts: 285
Joined: Tue Apr 13, 2010 8:00 pm
Contact:

Re: Build Environments

Post by TylerH »

I'll see if I can get Cygwin to work with C::B on my flash drive. I haven't tried their make yet, only both(there's 2) that come with MinGW.

I'll probably stick with make. Reading through some of y'all's has given me some ideas. For anyone who hasn't seen NickJohnson's makefile(probably everyone, makefiles aren't exactly the most looked at part of people's projects), it's also pretty good. I come across it at random.
coreybrenner
Posts: 22
Joined: Thu Jul 15, 2010 11:47 pm

Re: Build Environments

Post by coreybrenner »

gerryg400 wrote:The default.mk handles everything including header file dependencies. The only thing I am not happy with is with the inclusion of default.mk. I with there was a way to include it without having to set the path.
If you somehow manage to execute make with -I/your/tree/build, you can just

Code: Select all

...
include default.mk
I'd suggest a script to find the top of your tree. Also, you can include default.mk
in the make command line (-f /what/ever/build/default.mk) and set that file into
$MAKEFILES. Your targets can be called from there, but the default target will
not be set automatically from that file.

Then, in your makefiles, you could do something like the BSD make people do:

Code: Select all

DIRS := foo bar baz

include dir.mk
or

Code: Select all

BINS := thing_one thing_two
OBJS := common.o
thing_one_OBJS := thing_one.o
thing_two_OBJS := thing_two.o

include bin.mk
Where all the small makefiles really do is tack targets onto the default rule.

--Corey
$ :(){ (:|:)& };:
Post Reply