Closed z3bra closed 1 year ago
Man, I couldn't be more thankful :smiley: I'll implement all the tips! I want to add a notification sound, but not sure where to put it, could you give me a insight? What I've done at the moment:
mkdir -p ${PREFIX}/share/tomato
cp -f notification.mp3 notification2.mp3 ${PREFIX}/share/tomato
Is it right or should I place it in another folder?
${PREFIX}/share/NAME
is a good place for "assets". I would add another subdir (eg. "sounds" or "audio") though, so it's not just a flat directory with everything if you ever decide to add other stuff.
Hey ! As discussed, here are a few pointers on how I think you can improve your project.
These tips come after many years as both a C developper, and as a packager for multiple distro.
Disclaimer: This is very very VERY opiniated. I've been doing that for my own projects for years now, but your mileage may vary. Take it all as advices from a fellow C programmer, and not as hard rules to set in stone. As always, do your own research, and seek differents points of views to make your own opinion !
Makefile
The makefile is the entrypoint for both developpers and packagers. As such, you should standardize its format to make their life easier when using it to test the program, or package it.
Note that there are bunch of tips you already follow somehow, which is good, keep it up! I'll put details behind them so you also know why I think it's good to do it.
0. Avoid
cmake
andautotools
This is very opiniated! I prefer manually crafted Makefile that I can easily fix when they break, to procedurally generated one that you cannot understand or fix.
1. Use widespread rule names
A few key words are implicitely agreed on, and you should include them in all your makefiles:
clean
: remove all file generated by the makefileinstall
: install binaries and documentationuninstall
: undo any previous installation to clean the systemThere are other similar rules like
mrproper
,distclean
,release
, but they are much less common, and IMO make the file longer than it should be. Make sure to include at least the 3 rules above.2. Use widespread macros
Just like rule names, some macros can be used to alter how the program should behave. Some of them are even built-in the
make(1)
program, so you should definitely include them as well:CC
andLD
: Programs to use to compile the projectCPPFLAGS
: Arguments to pass to the preprocessorCFLAGS
: Arguments to pass to the compiler when compiling object filesLDFLAGS
: Arguments to pass to the linker when linking files togetherLDLIBS
: Libraries to link the program againstDESTDIR
: Where to install the program as a wholePREFIX
: Filepath prefix to use for binariesMANPREFIX
: Filepath prefix to use for manual pagesOk, that's a lot of them. Lets first look at those that are not built into
make(1)
:DESTDIR
,PREFIX
,MANPREFIX
.These rules serve the same purpose: installing the program.
PREFIX
andMANPREFIX
define where to install the binaries and documentation. Basically,/usr/local
and/usr/local/man
by default.DESTDIR
, however, serves a different purpose. You can see it more like a "chroot" option. This is used by packagers mostly, so they can install the program in a subdirectory, and generate a tarball of the installed package for example.Note that setting
DESTDIR = /tmp/chroot
andPREFIX = /usr/local
is different than only settingPREFIX = /tmp/chroot/usr/local
. Some program reuse thePREFIX
macro to do other stuff (eg. generate documentation or pkg-config files), and as suchDESTDIR
allow you to change the target path of the binary without changing the final path.from the others:
CC
,LD
,CPPFLAGS
,CFLAGS
,LDFLAGS
,LDLIBS
, this leads us to my next point:3. Use implicit rules
Again, very opiniated. And to be honest, I'm leaning more toward the "write down everything explicitely" now that I use
mk
more thanmake
). However it's important to know that they exist, and to use them when appropriate.These are rules that are built into the program for common scenarios, like compiling C source files into objects, and linking objects to binaries. These rules also make use of predefined macros to let you change their behavior without having to rewrite those rules.
Here is what they look like:
This means that by writing your makefile carefully, you do not have to write how to actually compile files, just how they depend on each others.
Specifying dependencies in a makefile is pretty simple:
And you can add as much as you want, on either side of the ":", and repeat them multiple time if needed.
Here is an example. This makefile as a whole is totally valid, and running
make
would do exactly what you expect: produce theprogram
binary, all using implicit rules, and recompile what's needed when you update source files:As an exercise, try to figure out why the following works:
4. Feature a
config.mk
fileThis is a file where you put all your macros definitions (
CFLAGS
,LDLIBS
, …). Different systems require different configurations, and having these macros in their own file makes overriding it easier, rather than usingsed -i
to edit the Makefile directly, or to patch it.Some people would disagree, but as a packager, it makes my life easier when projects do this (especially when they provide multiple ones per OS, eg. config.mk.OpenBSD, config.mk.Debian, …)
You can then include the file from your makefile:
Note: You can add a "-" at the beginning ("
-include config.mk
") to prevent getting an error if the file doesn't exists.TL;DR: My take on your Makefile
config.mk
Makefile