Well, I had a really good one today. Thankfully, I only wasted about an hour.
Here's the outline: I have a userspace driver that does some relatively generic things that I compiled as a dynamic library (let's call it libmydev_ctrl.dylib). On top of that, I have a device-specific userspace driver for specific functionality that I compiled as a dynamic library (let's call it libmydev_ctrl_spec.dylib). On top of that, I have binaries that use device-specific drivers (let's call it myexecutable).
Compiling is fairly straightforward. First, the "generic" dylib:
12345678910 | DYLIB_ALL_NAME := libmydev_ctrl.dylib
TARGET_DYLIB_ALL := $(TARGET_DIR)/$(DYLIB_ALL_NAME)
INST_DYLIB_ALL := $(INSTALL_DIR)/$(DYLIB_ALL_NAME)
$(TARGET_DYLIB_ALL): $(OBJECTS_ALL) | $(TARGET_DIR)
@printf "%-16s %-8s %s\n" "link" "LLD" $(notdir $@)
@$(COMPILER) -o $@ \
-install_name $(INST_DYLIB_ALL) -dynamiclib \
$^ $(FLAGS) $(INCLUDES) $(LIBRARIES)
|
And then we do something very similar to compile the device-specific dylib; as you can see, the only real difference in the makefile is that the "generic" dylib is a pre-requisite of the "specific" dylib:
12345678910 | DYLIB_PLAT_NAME := libmydev_ctrl_$(TARGET_NAME).dylib
TARGET_DYLIB_PLAT := $(TARGET_DIR)/$(DYLIB_PLAT_NAME)
INST_DYLIB_PLAT := $(INSTALL_DIR)/$(DYLIB_PLAT_NAME)
$(TARGET_DYLIB_PLAT): $(OBJECTS_PLAT) $(TARGET_DYLIB_ALL) | $(TARGET_DIR)
@printf "%-16s %-8s %s\n" "link" "LLD" $(notdir $@)
@$(COMPILER) -o $@ \
-install_name $(INST_DYLIB_PLAT) -dynamiclib \
$^ $(FLAGS) $(INCLUDES) $(LIBRARIES)
|
Finally, we compile the binary/executable; we make the "generic" and "specific" dylibs pre-requisites, along with the source file with the main function:
1234 | $(TARGET): $(TARGET_DYLIB_ALL) $(TARGET_DYLIB_PLAT) $(SRC)
@printf "%-16s %-8s %s\n" "compile/link" "C++/LLD" $(notdir $@)
@$(COMPILER) -o $@ $^ $(FLAGS) $(INCLUDES) $(LIBRARIES)
|
If you're trying to follow along without make, the commands look like this:
1234567891011121314151617181920 | c++ -o libmydev_ctrl.dylib \
-install_name /usr/local/opt/libmydev_ctrl.dylib -dynamiclib \
source1.o source2.o source3.o \
-Wall -Werror -Wextra -Wno-unused-variable \
-Wno-unused-parameter -Wno-unused-function \
-Wno-unused-private-field \
-std=c++1y -g
c++ -o libmydev_ctrl_spec.dylib \
-install_name /usr/local/opt/libmydev_ctrl_spec.dylib -dynamiclib \
spec_source.o libmydev_ctrl.dylib \
-Wall -Werror -Wextra -Wno-unused-variable \
-Wno-unused-parameter -Wno-unused-function \
-Wno-unused-private-field \
-std=c++1y -g
c++ -o myexecutable libmydev_ctrl.dylib libmydev_ctrl_spec.dylib dostuff.cpp \
-Wall -Werror -Wextra -Wno-unused-variable -Wno-unused-parameter \
-Wno-unused-function -Wno-unused-private-field -std=c++1y -g
|
But what falls out? Not good things. Solution after the jump:
1234567 | dyld: lazy symbol binding failed: Symbol not found: __Z4init8dev_type
Referenced from: myexecutable
Expected in: /usr/local/opt/libmydev_ctrl.dylib
dyld: Symbol not found: __Z4init8dev_type
Referenced from: myexecutable
Expected in: /usr/local/opt/libmydev_ctrl.dylib
|
I am 100% guilty of this. A worthy read.
"This is a veiled way of saying that Apple products are successful not because they are good products, but because Apple knows how to persuade their fanbase to buy them."