Handling whitespace in GNU Make foreach

40 Views Asked by At

I want to write a generic Makefile for OpenSCAD 3D designs.

Those designs consist of a .scad file and a corresponding .json file, which contains parameter sets.

The Make file should create a folder named output and call OpenSCAD for each parameter set found in the .json file.

So far I've come up with this:

# Parametric OpenSCAD design file
OPENSCAD_FILE = hsw_parametric_hook.scad

# JSON file containing parameter sets
PARAMETER_SETS_FILE = hsw_parametric_hook.json

# Output directory for generated STL files
OUTPUT_DIR = output

# Function to extract parameter set names from the JSON file
get_parameter_set_names = $(shell jq -r '.parameterSets | keys[]' $(PARAMETER_SETS_FILE))

# Function to construct the STL filename for a given parameter set
stl_filename = $(OUTPUT_DIR)/$(basename $(OPENSCAD_FILE))-$(1).stl

.PHONY: all clean

all: $(OUTPUT_DIR) $(foreach set,$(call get_parameter_set_names),$(call stl_filename,$(set)))

$(OUTPUT_DIR):
    mkdir -p $@

$(call stl_filename,%): $(OPENSCAD_FILE) $(PARAMETER_SETS_FILE)
    openscad -o $@ $(OPENSCAD_FILE) -p $(PARAMETER_SETS_FILE) -P '$(subst .stl,,$(subst $(subst .scad,,$(OPENSCAD_FILE))-,,$(@F)))'

clean:
    rm -f $(OUTPUT_DIR)/*.stl

The problem with this is, that it can't handle parameter set names containing a space character. I guess quoting is missing or messed up somehow.

Could anyone tell me how I could fix this?

The current directory could also contain more than one set of .scad and .json files. I would like the Makefile to be able to handle this as well and ideally not have those filenames hard-coded, as they are right now.

Any suggestions?


Update 2024-03-29:

I've incorporated a suggestion from @JohnBollinger to add a missing dependency, though it is unrelated to the issue.

I also created a more complete example, as requested by @MadScientist:

cylinder.scad

diameter = 10;
heigh = 5;

cylinder(d=diameter, h=height);

cylinder.json

{
    "parameterSets": {
        "Wide cylinder": {
            "diameter": "20",
            "height": "5"
        }
    },
    "fileFormatVersion": "1"
}

Makefile

# Parametric OpenSCAD design file
OPENSCAD_FILE = cylinder.scad

# JSON file containing parameter sets
PARAMETER_SETS_FILE = cylinder.json

# Output directory for generated STL files
OUTPUT_DIR = output

# Function to extract parameter set names from the JSON file
get_parameter_set_names = $(shell jq -r '.parameterSets | keys[]' $(PARAMETER_SETS_FILE))

# Function to construct the STL filename for a given parameter set
stl_filename = $(OUTPUT_DIR)/$(basename $(OPENSCAD_FILE))-$(1).stl

.PHONY: all clean

all: $(OUTPUT_DIR) $(foreach set,$(call get_parameter_set_names),$(call stl_filename,$(set)))

$(OUTPUT_DIR):
    mkdir -p $@

$(call stl_filename,%): $(OPENSCAD_FILE) $(PARAMETER_SETS_FILE) $(OUTPUT_DIR)
    openscad -o $@ $(OPENSCAD_FILE) -p $(PARAMETER_SETS_FILE) -P '$(subst .stl,,$(subst $(subst .scad,,$(OPENSCAD_FILE))-,,$(@F)))'

clean:
    rm -f $(OUTPUT_DIR)/*.stl

Running make now, creates the following output:

openscad -o output/cylinder-Wide.stl cylinder.scad -p cylinder.json -P 'Wide'
Geometries in cache: 1
Geometry cache size in bytes: 2456
CGAL Polyhedrons in cache: 0
CGAL cache size in bytes: 0
Total rendering time: 0:00:00.000
   Top level object is a 3D object:
   Facets:         18
openscad -o output/cylinder-cylinder.stl cylinder.scad -p cylinder.json -P 'cylinder'
Geometries in cache: 1
Geometry cache size in bytes: 2456
CGAL Polyhedrons in cache: 0
CGAL cache size in bytes: 0
Total rendering time: 0:00:00.000
   Top level object is a 3D object:
   Facets:         18
0

There are 0 best solutions below