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.

Mare
  • 943
  • 3
  • 11
  • 18
  • Shouldn't ${AR} be at the very beginning of the line? After all, it's the command, isn't it? – celtschk Mar 06 '12 at 23:18
  • 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. – Kaz Mar 06 '12 at 23:18
  • 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`? – Beta Mar 06 '12 at 23:21
  • 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. – Kaz Mar 06 '12 at 23:21

2 Answers2

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.

Beta
  • 96,650
  • 16
  • 149
  • 150
  • 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 http://msdn.microsoft.com/en-us/library/ms235627.aspx so could there still be something wrong with my linking ? – Mare Mar 07 '12 at 21:51
  • or should I somehow create dll as here http://msdn.microsoft.com/en-us/library/ms235636.aspx ? – Mare Mar 07 '12 at 22:31
  • 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... – Beta Mar 07 '12 at 22:38
  • 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 :/ – Mare Mar 07 '12 at 23:02
  • 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. – Mare Mar 08 '12 at 20:52
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
Kaz
  • 55,781
  • 9
  • 100
  • 149
  • @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 that – Hossein Apr 08 '20 at 04:44
  • 1
    @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. – Kaz Apr 08 '20 at 17:23
  • 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. – Hossein Apr 08 '20 at 18:06
  • 1
    @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. – Kaz Apr 08 '20 at 19:58
  • 1
    @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. – Kaz Apr 08 '20 at 20:00
  • @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 :) – Hossein Apr 09 '20 at 04:50
  • @Kaz, I guess I got it right this time, : https://pastebin.com/tt41BBax – Hossein Apr 09 '20 at 05:00
  • @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)/`. – Kaz Apr 09 '20 at 15:46
  • 1
    @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. – Kaz Apr 09 '20 at 15:49
  • Thanks a lot can you point me to somewhere where I can read more about this? I greatly appreciate your kind help :) – Hossein Apr 09 '20 at 16:07