0

This is my first time asking a question here, as I'm usually able to find answers in previous posts, but I can't find any information on this topic.

I'm trying to write C/C++ header files that can be reused between projects. One of my headers uses <math.h> (deprecated in C++, so it uses <cmath> instead). When I compile a C++ program to test the header, it works perfectly. When I compile a C program to test the header, the linker rightfully throws a fit unless "libm.a" is linked ("-l m" in most compilers). I'm not worried about myself forgetting to link the library, but I plan on making these headers available for public use, and I'd like to print a more helpful error message than "undefined reference". Here's my question, is there any way for me to use something akin to preprocessor directives to check if a specific library is linked properly when building the executable so I can throw my own error message?

Source code: https://github.com/LimikEcho/rlx/blob/main/itosa.h

I've tried checking if specific macros are defined (from both <math.h> and <math.c>). If I check a macro defined in <math.h>, it returns 1 regardless of linking "libm.a". If I check a macro defined in <math.h>, it returns 0 regardless of linking "libm.a". I understand why that is, but it was worth a shot.

Edit: People seem to be missing the point of this, so let me reiterate. I want to know if it's possible to influence the error handling of the linker from a header, that way whenever it's used by third parties, they can be accurately warned about missing a specific library. I want to display undefined reference errors as something like undefined reference to 'example_function', did you forget to link 'libm.a'?

Skeptx
  • 63
  • 5
  • 2
    You can't catch at compile time that which can only be found missing at link time. The compiler compiles one compilation unit at a time with no knowledge of the whole program. It is not until link time the all the parts come together and any missing symbols can be reported. This is why many programs are supplied with _"build files"_ and documentation on how to build the program. – Richard Critten Nov 17 '22 at 21:16
  • The compiler can be run separately from the linker making this doubly hard. Compile time check would say, "linker flag is missing!" because no one specified the linker flag because no one was linking yet. – user4581301 Nov 17 '22 at 21:21
  • How many projects are you working on where you'd "forget" to link something? Usually you'll have a tried-and-tested `Makefile` or equivalent on hand that includes all these things by default, or at least has easily uncommentable sections, and can be trimmed back if necessary. – tadman Nov 17 '22 at 21:30
  • I'd personally use eg cmake for build logic and there you can verify a lib's existence before linking to it, for example: https://stackoverflow.com/a/56241734/3314252 – firmament Nov 17 '22 at 21:47
  • The compiler builds a table of *unresolved symbols*. The compiler has no idea if the symbol is resolved by another source file, a static library or a dynamic library. Resolving symbols is the job of the linker. – Thomas Matthews Nov 17 '22 at 22:31
  • I think you guys misunderstood the question because my title was misleading. I fixed it now. I understand the difference between compilation and linking, I write makefiles, and I give instructions when distributing code. You're giving the right answers to questions I didn't ask. I was asking if there was a way to influence the linker's handling of undefined reference errors through some sort of symbol or directive that the compiler would preserve. It does not seem like this is currently possible. Thank you all for the input. – Skeptx Nov 17 '22 at 23:22
  • Nothing in Standard C++ does this, but some compilers allow you to build in little hints [like Microsoft does with `#pragma comment`](https://stackoverflow.com/q/12199595/4581301). – user4581301 Nov 18 '22 at 00:14
  • @user4581301 `pragma comment` is the closest thing mentioned here to what I was hoping to find. I'll look into it more, thanks. – Skeptx Nov 18 '22 at 08:32
  • @habrewning I think the title didn't come out right, but I did mention in the post that I wanted to show a more helpful error message to users, "I plan on making these headers available for public use, and I'd like to print a more helpful error message". Most replies seem to gloss over the post and say something like "just use a makefile so you don't forget to link" when that has nothing to do with the premise. Thanks for your suggestions about this. – Skeptx Nov 18 '22 at 08:37

1 Answers1

0

The build process runs in different phases. The compilation phase takes your program code including the header file and produces a so called object files (with the file extension .o).

The same applies for your library. You get a set of object files. When you tell the compiler to produce a static library it takes a set of object files and put them all together into a static library (with the file extension .a).

When everything is compiled the linking phase is started. In that phase the object files and the static library is combined into one executable file.

That means, there is no way to check at the compilation phase the existence of the static library file. Because that file comes into game at the linking phase. The compilation needs only the header file. And this was not your question.

If a mechanism for loading libraries is needed, you must use a build tool like make. These give you the comfort you are asking for. But such tools normally don't have the purpose to integrate foreign static libraries, although this should be possible.

But what you try to achieve is also not advisable. It is not guaranteed that it will work if you and who uses the static library uses different versions of the compiler or different compiler options. The code of a static library is directly integrated into a binary. The linker integrates it for you. This requires 100% compatibility between both compilers. As far as I know, there is no mechanism that protects you from incompatibilities. Your use case is relatively exotic. It is no simple question to tell you what could go wrong with it (see also this not answered question: Static link library compatibility with newer compiler versions).

If you don't want to deliver the source code of your library, then you should consider shared libraries. Shared libraries are exactly made for the purpose you are asking for. You link them at runtime. The operating system does it. And you can also check at runtime if they exist or not.

On Windows shared libraries have the file extension .dll. On Linux they have the file extension .so.

For more information see Difference between static and shared libraries? and How do I find out what all symbols are exported from a shared object?.

Partial Solution

The following solution could give you at least some sort of indication when forgetting to link against a.

Your library header a.h is this:

void please_link_a();

void your_library_function();

Your library code a.c is this:

void please_link_a(){
  return;
}

void your_library_function() {
  return;
}

But then you don't give a.h to the users of your library. Instead you modify it by adding something that triggers a linker warning against please_link_a. So you give a file alib.h with the following contents.

void please_link_a();

void check_if_a_linked(){
  please_link_a();
}

What the user now forgets to link the static library, he sees all the linker errors for his code, but in addition this error:

/usr/bin/ld: /tmp/cczi8mca.o: in function `check_if_a_linked':
main.c:(.text+0xa): undefined reference to `please_link_a'

If it is not your own library, you cannot achieve the please_link_a part of the message. But the check_if_a_linked part you can. Just call anything else from the library. You can always manually change the header file that you got from the author and add such a function. But I don't know if this is practical for you. The linker error is still not so nice.

habrewning
  • 735
  • 3
  • 12
  • I wasn't asking about the preprocessor itself, but if something of a similar nature existed for the linker. I mentioned that this check would have to occur while building the executable (after compiling the object files, of course), that being linking. The title is misleading, ig it should ask "can you influence the linker's behavior from a file to throw custom errors for a missing library". Debugging symbols survive compilation, I hoped something similar could be read by the linker. I gather there's nothing like it in any current C/C++ compiler, maybe the future. Thank you for the input. – Skeptx Nov 17 '22 at 22:57
  • Nice, that's a cheeky workaround that I never would have thought of. Sadly, because I'm referring to a library that I didn't write, I won't be able to use that partial solution for my case. – Skeptx Nov 18 '22 at 08:29