Jamfile help

I am continuing my rEFind theme, and for that I want to start packaging the icons in apple ICNS files since this is the only rEFInd supported format that allows severall icon sizes (and it want this for bugger than full-hd screens)

To achieve this I have written a Jamfile!

Trouble is, it does not work(just “jam” only finds targets, and adding rules to call them didn’t work eirher), and I don’t know why. It also felt quite cumbersome in some places because actions can only take two arguments. Am I missing something? and what am i doing wrong?

actions MakePNGOS
{
	hvif2png -s 128 -i Sources/$(1) -o $(2)-128.png
	hvif2png -s 256 -i Sources/$(1) -o $(2)-256.png
	echo "doing something..."
}

actions MakeICNSOS
{
	png2icns $(iconname) $(iconname)-128.png $(iconname)-256.png
}

actions DeletePNGOS 
{
	rm $(1)-128.png
	rm $(1)-256.png
}

rule MakeOSIcon iconsource : iconname
{
	MakePNGOS $(iconsource) $(iconname) ;
	MakeICNSOS $(iconname) ;
	DeletePNGOS $(iconname) ;
}

actions MakePNGTool
{
	hvif2png -s 48 -i $(1) -o $(2)-48.png
	hvif2png -s 96 -i $(1) -o $(2)-96.png
}

actions MakeICNSTool
{
	png2icns $(iconname) $(iconname)-48.png $(iconname)-96.png
}

actions DeletePNGTool
{
	rm $(1)-48.png
	rm $(1)-96.png
}

rule MakeToolIcon iconsource : iconname
{
	MakePNGTool $(iconsource) $(iconname) ;
	MakeICNSTool $(iconname) ;
	DeletePNGTool $(iconname) ;
}

actions MakePNGOverlay
{
	hvif2png -s 32 -i $(1) -o $(2)-32.png
	hvif2png -s 64 -i $(1) -o $(2)-64.png
}

actions MakeICNSOverlay
{
	png2icns $(iconname) $(iconname)-32.png $(iconname)-64.png
}

actions DeletePNGOverlay
{
	rm $(1)-32.png
	rm $(1)-64.png
}

rule MakeDriveOverlayIcon iconsource : iconname
{
	MakePNGOverlay $(iconsource) $(iconname) ;
	MakeICNSOverlay $(iconname) ;
	DeletePNGOverlay $(iconname) ;
}

MakeToolIcon Action_GoBack1.IOM 	: arrow_left.icns ;
MakeToolIcon Action_GoForward1.IOM	: arrow_right.icns ;
MakeToolIcon Alert_Info.IOM			: func_about.png ;
MakeToolIcon File_Patch.IOM			: func_bootorder.png ;
MakeToolIcon Action_Stop.IOM		: func_exit.png ;
MakeToolIcon Device_Ramdisk.IOM		: func_firmware.png ;
MakeToolIcon App_Installer.IOM		: func_install.png ;

MakeOSIcon Misc_FreeBSD.IOM		: os_freebsd.png ;
MakeOSIcon App_Old.IOM			: os_legacy.png ;
MakeOSIcon App_Generic_4.IOM	: os_unknown.png ;

MakeDriveOverlayIcon Misc_UEFI.IOM			: vol_efi.png ;
MakeDriveOverlayIcon Device_Pendrive.IOM	: vol_external.png ;
MakeDriveOverlayIcon Device_Harddisk.IOM	: 

The last line seems unfinished, is it just a copypaste error in the forum post?

Anyway, the next question is “what you are missing”.

Firs of all, you did not specify any dependencies. Unlike make, in jam, this is not automatic, it is up to rules to define dependencies between targets.

So, your rules must invoke the DEPENDS rule explicitly:

rule MakeToolIcon iconsource : iconname
{
	MakePNGTool $(iconsource) $(iconname) ;
	MakeICNSTool $(iconname) ;
	DeletePNGTool $(iconname) ;

    DEPENDS $(iconname) : $(iconsource) ;
}

Your use of rules is weird, because you put the source first and the target second. Usually it would be the other way around, which then allows you to use the $(<) and $(>) special name as the source (input) and destination (output) respectively, like stdin and stdout redirections in a shell. I think it doesn’t make a difference to Jam itself, but people reading your jamfiles will be less confused. This also matches the order used in makefiles.

A more fundamental problem: rules invoke other rules. They do not invoke actions explicitly. The actions for a rule are found because they have the same name as the rule.

Next, the actions. Your actions are not using the passed parameters directly, and instead generating filenames internally from them. This means the DEPENDS rule will not work, because the icon name you passed to it is not an actual filename. The things passed to actions should be the already resolved source and destination filenames.

Moreover, you have actions doing pretty much the same thing over and over again. Actions should be much simpler than that. You say that actions take only two parameters, this is not quite true. First, the two parameters to the actions are lists. So, if you want to generate multiple files from one rule, you can refer to them as $(1[1]), $(1[2]) and so on. Thi s will be useful for your ICNS rule where you want to put multiple png files in a single ICNS. Pass them as a list instead of generating their name inside an action.

But also, you can use variables.

In the rule, you set a variable for a given target:

   ICONSIZE on icon32.png = 32 ;
   MakePNG  icon32.png source.iom ;

Then in the MakePNG rule you can use that variable in your command line:

    hvif2png -s $(ICONSIZE) -i Sources/$(1) -o $(2)

Finally, you have path manipulation in your actions. This will also not work, because again it create a mismatch between the rule name and the corresponding file. Instead you need to use SEARCH (for inputs) and LOCATE (for output) variables.

So we should get something like this (untested because you didn’t provide any IOM files for testing):

# Basic rule and action to convert an IOM file from the Source directory into a png
# ICONSIZE must be set on the target (by a calling rule) to know which size to make.
rule MakePNG png : iom
{
	DEPENDS $(png) : $(iom) ;
	SEARCH on $(iom) = $(TOP)/Source ;
}

actions MakePNG
{
	hvif2png -s ${ICONSIZE} -i $(1) -o $(2)
}

rule MakeICNS icns : pngs
{
	DEPENDS $(icns) : $(pngs) ;
}

actions MakeICNS
{
	png2icns $(1) $(2)
}

# Finally we bind it all together with a temporary set of PNG files.
rule MakeIcon icns : iom : sizes
{
	TEMPORARY $(icns)-tmp1.png ;
	TEMPORARY $(icns)-tmp2.png ;
	ICONSIZE on $(icns)-tmp1.png = $(sizes[1]) ;
	ICONSIZE on $(icns)-tmp2.png = $(sizes[2]) ;
	MakePNG $(icns)-tmp1.png : $(iom) ;
	MakePNG $(icns)-tmp2.png : $(iom) ;
	MakeICNS $(icns) : tmp1.png tmp2.png ;
}

# And so the user of the rule doesn't have to remember the sizes, we can finally do this:
rule MakeOSIcon icns : iom 
{
	MakeIcon $(icns) : $(iom) : 128 256 ;
}

MakeOSIcon Misc_FreeBSD.IOM		: os_freebsd.png ;
MakeOSIcon App_Old.IOM			: os_legacy.png ;
MakeOSIcon App_Generic_4.IOM	: os_unknown.png ;

For testing I suggest starting small: explicitly invoke MakePNG and make sure that works. Then MakeICNS. And so on until you have good confidence on eahc part.

Jam isn’t running your rules because no targets are declared. Add a DEPENDS all : <your .icns files> ; line so Jam knows what to build.