2

Although I am not an experienced programmer in C, I have to use this language at work to build a static library which compiles both on SunOS and Win32. This library has just a few source files and their correspondent headers (let's say: a.c, b.c, a.h and b.h). The project compiles in both platforms and the library mylib.a is generated.

My problem is how to expose the implemented functions of mylib.a to other projects, because when I add both a.h and b.h I get some macro redefinition errors.

EDIT: I found that the macro redefinition error was because of a macro definition into the compilation command (not related to my headers) and it is solved :) But still I would like advice on organizing my source and header files.

My doubt is whether I modify a.h and b.h to be used externally or if I should create a header file specifically for declaring the interface of this library (let's say mylib.h). I would not like to overcomplicate the original headers, but I would not like to have to keep a different header in sync ... I would like to hear from more experienced C programmers about their patterns, advantages of each approach and whether there are other options.

Thank you in advance.

EDIT: seems I have not provided enough information; the schema below tries to show how my files are organised: each code file only includes its header, each header has a guard condition, each header includes a common header, this common header includes all headers.

// a.c ----
#include "a.h"

// b.c ----
#include "b.h"

// a.h ----
#ifndef GUARD_A_H
#define GUARD_A_H
  # include "liball.h"
  void function_prototypes_implemented_in_a();
#endif // GUARD_A_H

// b.h ----
#ifndef GUARD_B_H
#define GUARD_B_H
  # include "liball.h"
  void function_prototypes_implemented_in_b();
#endif // GUARD_B_H

// liball.h ----
#ifndef GUARD_LIBALL_H
#define GUARD_LIBALL_H
  # include <time.h>   // standard headers
  # include <stdioa.h>

  # include "a.h"      // all headers in this project
  # include "b.h"
#endif // GUARD_LIBALL_H
Gerardo Lima
  • 6,467
  • 3
  • 31
  • 47
  • 1
    Can you show us the errors and relevant code ? also do you use header guards ? – iabdalkader Nov 06 '12 at 11:28
  • "when I add both a.h and b.h I get some macro redefinition errors"? Definitely just keep the 2 separate header files, and fix them. **Each header file should be usable separately or together with any other header files,** so you need to give your macros better names, e.g. by prepending some letters to the front that indicate the "namespace" (neither C macros nor C identifiers in general have namespaces, so this is the best you can do). – j_random_hacker Nov 06 '12 at 11:33
  • 1
    It's common to have one or more public header files to be used by others using your library. Sometimes they are used stand-alone, sometimes they include private files. – Some programmer dude Nov 06 '12 at 11:35
  • And yes, it's a good idea to make a 3rd header that simply #includes the other two headers to simplify usage for users of the library. – j_random_hacker Nov 06 '12 at 11:51
  • @j_random_hacker, the original project was a mess, so I spent some time organizing the import clauses and put them all into a centralized header file (`liball.h`), to make it easier for me to keep track of each dependency... is it such a bad practice? – Gerardo Lima Nov 06 '12 at 12:08
  • The important thing is to not try to maintain two sets of headers for the same library. If you want to combine them and get rid of the two originals, that's fine; if you want to keep the two originals and require users to use them both, that's fine; if you want to keep the two originals and use a 2-line 3rd header that includes them both, that's fine. – j_random_hacker Nov 06 '12 at 12:23
  • Once centralized header works just fine, within a project, but if you do incremental builds (e.g. with `make`) then modifying that one header will cause your entire project to rebuild. Of course, that's probably not important for a small source-base, and for a large source base your one header file will be a monster anyway. – ams Nov 06 '12 at 12:42
  • One of the purposes of the centralized header is to minimize the builds... It is not that I declare prototypes into this file, it exists to `#include` the other headers (this pattern is used by VS10). – Gerardo Lima Nov 06 '12 at 12:48
  • 1
    That pattern is fine - it organises the files neatly, and minimizes the number of `#include` directives you have to have - but it does mean that every `.c` file depends on every `.h` file which means incremental rebuilds are more expensive. That's not a huge issue for most projects though, and has zero impact on a build from clean, so feel free to do that, if you wish. – ams Nov 06 '12 at 13:06

2 Answers2

5

You should have a public header, mylib.h, that only contains the definitions a user of the library needs to know.

You then have a private header, mylib-internal.h, that is used within your project. You should not try to keep the two "in sync", but rather have mylib-internal.h contain #include "mylib.h".

You should also name all your interface functions like mylib_initialize() etc., and ensure that all private, internal functions are either declared static, or else named _mylib_internal_whatever(), so that users don't get namespace clashes with other libraries.

ams
  • 24,923
  • 4
  • 54
  • 75
  • Nice point, @ams, but shouldn't functions implemented in `a.c` have their prototypes declared into `a.h`? Is this a bad practice? – Gerardo Lima Nov 06 '12 at 11:55
  • 1
    @GerardoLima Yes, that's the best practice *within* a project: it minimizes the amount of `.c` files you have to rebuild every time you modify a header file. But `mylib.h` is for users and corresponds 1-to-1 with `libmylib.a`, so that's more important. Duplication between header files is a maintenance problem, so if you're doing that you may be Doing It Wrong. – ams Nov 06 '12 at 12:39
  • Sorry, @ams, but still it is not clear to me. I liked your suggestion of creating an `internal.h` which imports the `external.h`, but should I declare all prototypes within these files or should I keep them into `a.h` and `b.h` and import those into `external.h`? This can be very tricky, I have over 10 years experience programming, but these subtleties of C sometimes make me look like a fool. – Gerardo Lima Nov 06 '12 at 12:55
  • You should have one declaration for each function, type, and macro. Duplication causes bugs, so don't do it. You should hide the definitions of anything a user of the library doesn't need to know, so don't put them in the external `mylib.h`, but you can put them wherever you choose: the source is yours. (If you expose internal details then some idiot user will rely on them and then you'll never be able to change them without breaking his app.) – ams Nov 06 '12 at 13:01
0

You're question is too vague so my answer is a generic advice, you should avoid double inclusion and use include guards in the headers, like so:

a.h

#ifndef __HEADER_A_H__
#define __HEADER_A_H__ 
...
#endif

b.h

#ifndef __HEADER_B_H__
#define __HEADER_B_H__ 
...
#endif

Edit: Like I said, avoid double (or circular) inclusion there's no need for liball.h to include a.h and b.h also, note that liball.h header guard is same as b.h, so b.h will not be defined at all !

iabdalkader
  • 17,009
  • 4
  • 47
  • 74
  • I already use guards, @mux. They work fine into the project that builds the library itself, but apparently they aren't preventing these erros. – Gerardo Lima Nov 06 '12 at 12:02
  • I added some more information about how my source is organized, maybe it can help find the cause of the problem. – Gerardo Lima Nov 06 '12 at 12:02
  • the problem with the liball guard does not exist in my project (it was a quick edit misspell, and it is corrected now). The reason I include `a.h` and `b.h` into `liball.h` is because some functions of `a` are used in `b` and likewise -- actually, there are 5 source (C) files. – Gerardo Lima Nov 06 '12 at 12:22