Creating a library file in makefile and compiling after that
Asked Answered
C

2

4

My problem is fairly easy but I just don't know how to solve it. I know how to compile and library and link against it if I'm not using a make file because then I can just call ar separately and everything goes right.

Anyway I'm using a petsc library and I'm using a makefile what they provided:

CFLAGS          = 
FFLAGS          = 
CPPFLAGS        = 
FPPFLAGS        =
LOCDIR          = /home/user/.../.../   # Working folder
EXAMPLESC       = main.cpp class.cpp        #.cpp file names here
EXAMPLESF       =
#MANSEC          = Mat I don't know what this is but it seems to work without it.

include ${PETSC_DIR}/conf/variables
include ${PETSC_DIR}/conf/rules

myProgram: main.o class.o  chkopts
    -${CLINKER}  -o myProgram main.o class.o ${PETSC_MAT_LIB}
    ${RM} main.o class.o

include ${PETSC_DIR}/conf/test

ARFLAGS will be -rv as a default so where should I provide such a information as

ar -rv libclassdll.a class.o

and where should I add -L./-lclassdll ?

I'm quite a rookie with makefiles so that's why I'm a bit lost here :<

I tried to change the line to

myProgram: main.o class.o  chkopts
    -${CLINKER}  -o myProgram main.o class.o ${AR} libclassdll.a class.o ${PETSC_MAT_LIB}
    ${RM} main.o class.o

and then my compiling command seems to be mpicxx -o myProgram main.o class.o /usr/bin/ar/ libclassdll.a class.o -L ( a lot of linking here ) and at least it says: g++ classdll.a no such a file or dir.

So it doesn't generate even a lib file for me. So any ideas will be really appreciated.

A new problem when I uploaded makefile on the different machine, my current makefile looks like this

LibMyClass.so: MyClass.o  chkopts
    -${CLINKER}  -shared -Wl,-soname,${SONAME} -o ${VERS}   *.o  ${PETSC_MAT_LIB}

    mv ${VERS} ${LIBADD}
    ln -sf ${LIBADD}${VERS} ${LIBADD}${SOWOV}
    ln -sf ${LIBADD}${VERS} ${LIBADD}${SONAME}

That works on one machine but other machine gives following error

/usr/bin/ld: MyClass.o: relocation R_X86_64_32S against `.rodata' can not be used when making a shared object; recompile with -fPIC
MyClass.o: could not read symbols: Bad value

I did change the paths of course but I guess that indicates other kind of problem because even if I type "g++ -shared -Wl,-soname,libmyclass.so.1 -o libmyclass.so.1.0 MyClass.o" or "g++ -fPIC -share... " I'll get the same error.

Crapulent answered 6/3, 2012 at 22:57 Comment(4)
Shouldn't ${AR} be at the very beginning of the line? After all, it's the command, isn't it?Cyclamen
You've already included class.o among the object files linked to produce the program executable, so it's pointless/redundant to also link a library which is made out of class.o.Kandacekandahar
If you'd already constructed the library with ar and compiled main.o, what command would you use to link them together and build myProgram?Goldston
Do not delete your object files in the rule which links the program. This is a silly thing to do and largely defeats the point of using make. Make is a tool which performs incremental rebuilds of your program based on rules. If you blow away the intermediate object files each time you build, you might as well just build with a script. Or just "cc *.c -o myprogram" type approaches.Kandacekandahar
G
6

Ideally you should construct the library first, then use it, just as you would "by hand".

To construct (or update) the library, you need a rule something like this:

libclassdll.a: class.o
    ar -rv libclassdll.a class.o

Or more concisely, like this:

libclassdll.a: class.o
    ar $(ARFLAGS) $@ $^

Then the rule for myProgram becomes:

# Assuming CLINKER is something civilized, like gcc
myProgram: main.o libclassdll.a  chkopts
    -${CLINKER} -o myProgram main.o -L. -lclassdll ${PETSC_MAT_LIB}

or better:

myProgram: main.o libclassdll.a  chkopts
    -${CLINKER} -o $@ $< -L. -lclassdll ${PETSC_MAT_LIB}

So in your makefile, you would replace

myProgram: main.o class.o  chkopts
    -${CLINKER}  -o myProgram main.o class.o ${PETSC_MAT_LIB}
    ${RM} main.o class.o

with

myProgram: main.o libclassdll.a  chkopts
    -${CLINKER} -o $@ $< -L. -lclassdll ${PETSC_MAT_LIB}

libclassdll.a: class.o
    ar $(ARFLAGS) $@ $^

There are other refinements you can make, but that should be enough for now.

Goldston answered 6/3, 2012 at 23:35 Comment(5)
For some reason I still get following error while compiling: undefined reference to MyClass::Class::Function() ... I've searched many ways to use the functions outside of the lib and I now I'm following msdn.microsoft.com/en-us/library/ms235627.aspx so could there still be something wrong with my linking ?Crapulent
or should I somehow create dll as here msdn.microsoft.com/en-us/library/ms235636.aspx ?Crapulent
So when you compile & link by hand there is no error, but when you use the makefile you get this error, correct? If so then look at the four targets: 1) main.o, 2) class.o, 2) the library, 3) myProgram. Try building some by hand, some by Make, find the one(s) responsible, and tell us the results...Goldston
Actually even compiling by hand there's error with linking. I'm assuming that maybe I should use .so instead of .a but unfortunately I need to go now. I'll get back to this issue later. I was just testing that msdn dll example with www.gamedev.net/topic/327323-how-to-create-and-use-a-dll-with-c-/ and still got linking error :/Crapulent
Actually I just followed dll instructions yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html from here and now everything works! But I have a new problem which I updated to the first post when I moved makefile on other computer.Crapulent
K
3

Make myProgram depend on main.o and on the libclass.a (don't call it libclassdll.a; it is not a DLL, but a static library).

General gist of the solution:

# $@ means "the target of the rule"
# $^ means "the prerequisites: main.o and libclass.a"

myProgram: main.o libclass.a
        $(CC) -o $@ $^ # additional arguments for other libraries, not built in this make

libclass.a: class.o
        # your $(AR) command goes here to make the library
Kandacekandahar answered 6/3, 2012 at 23:26 Comment(10)
@kaz,thanks How do you changed the ar output dir? I want to move all files in the build directory. gcc has the -o switch but ar doesn't seem to have any switches for thatNardone
@Rika ar takes the archive file name as its first non-option argument, so it require no -o option. In the above Makefile, the archive name is fixed as the libclass.a target name. In the libclass.a rule, it would be referenced as $@, which would be passed to $(AR) as the first non-option argument. To change its location, we would rename the target. make has to stay informed about where everything is; we don't want to move output files behind make's back.Kandacekandahar
Thanks a lot really appreciate it :) . I myself ended up doing sth like this : libcore.a: Core.o ar rcsv libcore.a $(BUILD_DIR)/Core.o && mv ./libcore.a $(BUILD_DIR) it links and then moves into the build_dir.Nardone
@Rika Problem is, the rule now no longer updates the libcore.a target which it promises to do. It's effectively a phony target; you can mark it .PHONY (and perhaps give it simpler name name like libcore). When a target is phony, make doesn't test for the existence of it as a file.Kandacekandahar
@Rika Also, if the goal of the rule is that there is a $(BUILD_DIR)/libcore.a, then why wouldn't you make that path the rule's target, and also a prerequisite of other rules which link with that library? Moreover, if Core.o is really $(BUILD_DIR)/Core.o then the prerequisite line is also lying, unless VPATH is being used to find prerequisites in multiple directories.Kandacekandahar
@Kaz: Thaks a lot. really appreciate it. actually I just started Makefile and I really dont know much about it. I thought tha'ts a viable choice since the compilation was ok! it seems its not! I'll change them accordingly then. thanks a lot :)Nardone
@Kaz, I guess I got it right this time, : pastebin.com/tt41BBaxNardone
@Rika That looks fine at a cursory glance. In a big project with lots of .o files we would normally do something like OBJS := $(addprefix $(BUILD_DIR),foo.o bar.o parser.o lexer.o ...) to reduce the proliferation of $(BUILD_DIR)/.Kandacekandahar
@Rika Instead of -c $(CORE_CPP) -o $(BUILD_DIR)/Core-dll.o you can use the target automatic variables -c -o $@ $^. $^ expands to all the prerequisites of the rule, and $@ to the target.Kandacekandahar
Thanks a lot can you point me to somewhere where I can read more about this? I greatly appreciate your kind help :)Nardone

© 2022 - 2024 — McMap. All rights reserved.