Dynamic Command Loading

Posted by Samson on Sun 11 Jun 2006 10:22 PM — 5 posts, 15,703 views.

USA #0
The following Makefile:

#AFKMud dynamically loaded commands.
#This makefile can be invoked directly, or via the makefile in the src directory.
#
#Takes any existing cpp files in this directory and makes dynamically loadable .so files out of them.

#Type of machine to compile for. Athlon works just as well on Duron too.
#The march option needs to match the general family of CPU.
#If you don't know what to set for these options, and your system administrator doesn't either, comment this line out
MACHINE = -march=athlon-xp

# Uncomment the two lines below if compiling on a Solaris box
#SOLARIS_FLAG = -Dsun -DSYSV -Wno-char-subscripts
#SOLARIS_LINK = -lnsl -lsocket -lresolv

#IMC2 - Comment out to disable IMC2 support
IMC = 1

#Internal Web Server - comment out to disable web server code.
WEB = 1

#Multiport support. Comment out to disable this feature.
MULTIPORT = 1

#Miscellaneous compiler options.
OPT_FLAG = -fpic -pipe -Os
DEBUG_FLAG = -g2
#PROF_FLAG = -pg

W_FLAGS = -Wall -Wextra -Wformat=2 -Wshadow -Wpointer-arith -Wcast-align -Wcast-qual -Wredundant-decls -Wconversion

C_FLAGS = $(MACHINE) $(W_FLAGS) $(DEBUG_FLAG) $(OPT_FLAG) $(PROF_FLAG) $(SOLARIS_FLAG)
C_FILES := $(wildcard *.cpp)
O_FILES := $(patsubst %.cpp,o/%.o,$(C_FILES))
SO_FILES := $(patsubst o/%.o,so/%.so,$(O_FILES))

ifdef WEB
   C_FLAGS := $(C_FLAGS) -DWEBSVR
endif

ifdef IMC
   C_FLAGS := $(C_FLAGS) -DIMC
endif

ifdef MULTIPORT
   C_FLAGS := $(C_FLAGS) -DMULTIPORT
endif

all:
	$(MAKE) -s obj
	$(MAKE) sobj
	@echo "Done building modular commands.";

obj:	$(O_FILES)

sobj:	$(SO_FILES)

clean:
	@rm -f o/*.o so/*.so
	$(MAKE) all

purge:
	@rm -f o/*.o so/*.so

o/%.o: %.cpp
	@echo "  Compiling $@....";
	g++ -c $(C_FLAGS) $< -o $@

so/%.so: %.o
	@echo "  Linking $@....";
	g++ -shared $< -o $@


Produces the following error:
Quote:

[samson@boralis: ~/Alsherok/src/cmd] make clean
make all
make[1]: Entering directory `/home/samson/Alsherok/src/cmd'
make -s obj
make[2]: Entering directory `/home/samson/Alsherok/src/cmd'
Compiling o/do_aexit.o....
Compiling o/do_areas.o....
Compiling o/do_climate.o....
Compiling o/do_score.o....
make[2]: Leaving directory `/home/samson/Alsherok/src/cmd'
make sobj
make[2]: Entering directory `/home/samson/Alsherok/src/cmd'
g++ -c -o do_aexit.o do_aexit.cpp
Linking so/do_aexit.so....
g++ -shared do_aexit.o -o so/do_aexit.so
g++ -c -o do_areas.o do_areas.cpp
Linking so/do_areas.so....
g++ -shared do_areas.o -o so/do_areas.so
g++ -c -o do_climate.o do_climate.cpp
Linking so/do_climate.so....
g++ -shared do_climate.o -o so/do_climate.so
g++ -c -o do_score.o do_score.cpp
do_score.cpp: In function 'void do_score(char_data*, char*)':
do_score.cpp:23: error: 'class pc_data' has no member named 'imcchardata'
make[2]: *** [do_score.o] Error 1
rm do_areas.o do_climate.o do_aexit.o
make[2]: Leaving directory `/home/samson/Alsherok/src/cmd'
make[1]: *** [all] Error 2
make[1]: Leaving directory `/home/samson/Alsherok/src/cmd'
make: *** [clean] Error 2
[samson@boralis: ~/Alsherok/src/cmd]


The command:
Quote:

g++ -c -o do_score.o do_score.cpp


Should not be coming into this, and I can't figure out why it is. Anyone have any ideas?
USA #1
This dependency:
so/%.so: %.o
	@echo "  Linking $@....";
	g++ -shared $< -o $@
is being triggered, I think. That would explain why it's dropping back to compiling instead of linking.

So, for whatever reason, it's not finding the score object. Why is your dependency for %.o? Should it not be for o/%.o?

If you have object files left over in your directory from previous compiles, that would explain why the first set did not trigger the dependency, because it is indeed finding the object file.
USA #2
Well here's the thing. Take a close look:

Quote:

g++ -c -o do_climate.o do_climate.cpp
Linking so/do_climate.so....
g++ -shared do_climate.o -o so/do_climate.so


Notice how it is adding that 3rd command above where it says it's linking? Neither of the two blocks at the bottom of the makefile have a command format that matches it. So I don't get how it's able to do that.


Regardless, your suggestion on changing to o/%.o in the final block of the makefile did work and I was able to compile through and get properly working results. So thanks for that :)
USA #3
Hmm... make seems to have a built-in default rule for making object files. Check this out:
$ ls
Makefile  main.cpp
Now:
$ cat Makefile 

all: test

test: main.o
        g++ -o test main.o
And finally:
$ make
g++    -c -o main.o main.cpp
g++ -o test main.o


So, obviously it must have some way of just knowing that if it needs the o file, it tries to compile a source file with the same name.

This would also explain why the flags are not in the same order as your normal compiling blocks, which should look like this:
g++ -c $(C_FLAGS) $< -o $@


Learn something every day, huh? :-)
USA #4
Cool. At least now we know and will be able to spot this problem in the future should anyone try it. Doesn't make it any less confusing to troubleshoot though :P