views:

365

answers:

9

For a debugging and logging library, I want to be able to find, at runtime, a list of all of the source files that the project has compiled and linked. I assume I'll be including some kind of header in each source file, and the preprocessor __FILE__ macro can give me a character constant for that file, so I just need to somehow "broadcast" that information from each file to be gathered by a runtime function.

The question is how to elegantly do this, and especially if it can be done from C as opposed to C++. In C++ I'd probably try to make a class with a static storage to hold the list of filenames. Each header file would create a file-local static instance of that class, which on creation would append the FILE pointer or whatever into the class's static data members, perhaps as a linked list.

But I don't think this will work in C, and even in C++ I'm not sure it's guaranteed that each element will be created.

+4  A: 

I wouldn't do that sort of thing right in the code. I would write a tool which parsed the project file (vcproj, makefile or even just scan the project directory for *.c* files) and generated an additional C source file which contained the names of all the source files in some kind of pre-initialized data structure.

I would then make that tool part of the build process so that every time you do a build this would all happen automatically. At run time, all you would have to do is read that data structure that was built.

Ferruccio
Parse the vcproj is an extra job. Scan dir won't guarantee anything.
Mykola Golubyev
A: 

I don't think you can do this in the way you outline in a "passive" mode. That is, you are going to somehow run code for each source file to be added to the registry, it's hard to get it to happen automatically.

Of course, it's possible that you can make that code very unobtrusive using macros. It might be problematic for C source files that don't have an "entrypoint", so if your code isn't already organised as "modules", with e.g. an init() function for each module, it might be hard. Static initializing code might be possible, I'm not 100% sure if the order in which things are initialized creates problems here.

Using static storage in the registry module sounds like an excellent idea, a plain linked list or simple hash table should be easy enough to implement, if your project doesn't already include any general-purpose utility library.

unwind
It is possible to automate. See my answer.
Mykola Golubyev
A: 

In C++ your solution will work. It's guaranteed.

Edit: Just found out a solution in my head: Change a rule in your makefile to add '-include "cfiles_register.h"' to each 'g++ file.cpp'.

%.o : %.cpp
    $(CC) -include 'cfiles_register.h' -o $@ $<

put your proposed in the question implemnatation to that 'cfiles_register.h'.

Mykola Golubyev
+1  A: 

Theres no way to do it in C. In C++ you can create a class like this:

struct Reg {
   Reg( const char * file ) {
      StaticDictionary::Register( file );
};

where StaticDictionary is a singleton container for all your file names. Then in each source file:

static Reg regthisfile( __FILE__ );

You would want to make the dictionary a Meyers singleton to avoid order of creation problems.

anon
Why order in this case is a problem?
Mykola Golubyev
Because you need to make sure the static dictionary is created before you try to use it. Since you can't depend on order of creation of globals, you need to create it at first use via the singleton pattern.
Michael Kohne
Isn't StaticDictionary::Register will do this job?
Mykola Golubyev
+2  A: 

I agree with Ferruccio, the best way to do this is in the build system, not the code itself. As an expansion of his idea, add a target to your build system which dumps a list of the files (which it has to know anyway) to a C file as a string, or array of strings, and compile this file into your source. This avoids a lot of complication in the source, and is expandable, if you want to add additional information, like the version number from your source code control system, who built the executable, etc.

KeithB
A: 

Using static instances in C++ would work fine.

You could do this also in C, but you need to use runtime specific features - for MSVC CRT take a look at http://www.codeguru.com/cpp/misc/misc/threadsprocesses/article.php/c6945/

For C - you could do it with a macro - define a variable named corresponding to your file, and then you could scan the symbols of your executable, just as an idea:

 #define TRACK_FILE(name) char _file_tracker_##name;

use it in your my_c_file.c like this:

 TRACK_FILE(my_c_file_c)

and than grep all file/variable names from the binary like this

nm my-binary | grep _file_tracker

Not really nice, but...

siddhadev
+2  A: 

There is a standard way on UNIX and Linux - ident. For every source file you create ID tag - usually it is assigned by you version control system, e.g. SVN keywords.

Then to find out the name and revision of each source file you just use ident command. If you need to do it at runtime check out how ident does it - source for it should be freely available.

qrdl
A: 

Horrible idea, I'm sure, but use a singleton. And on each file do something like

  Singleton.register(__FILE__);

at global scope. It'll only work on cpp files though. I did something like this years ago as a novice, and it worked. But I'd cringe to do it now. I'd add a build step now.

Robert Gould
A: 

I agree with those who say that it is better to avoid doing this at run time, but in C, you can initialize a static variable with a function call, that is, in every file:

static int doesntmatter = register( __FILE__);
dmityugov
register is a keyword in c, and should generally be avoided
EvilTeach
yes, agree, took it from another answer, as it seems - blindly :-)
dmityugov