views:

291

answers:

5

The __FILE__ and __LINE__ macros are built into the C Pre-Processor, and are often used for printing debug output with file names and line numbers. I need something similar, but with just the name of the directory at the end of the path. For instance if my code is in: /home/davidc/some/path/to/some/code/foo/bar I need a macro that will just give me "bar", if the code is in /home/davidc/some/path/to/some/code/foo/bee then I need it to give me "bee".

Any thoughts? (btw, this is for a C++ application). Thanks!

Update: to be clear, I'm after a macro that will give me a string containing the directory name at compile-time, I don't want to do any string-processing at runtime.

+2  A: 

There is no built in macro for that, but obviously you can write your own little parsing routine which takes a file and rips out the directory name for a given full pathed filename. Lets call this function:

extern std::string parseLastDir (const char *path);

Then you can make a macro like this:

#define __DIR__ parseLastDir (__FILE__)

which will sort of behave like what you want (it gives you a std::string instead of a char * so that cleaning up is better defined) with the relevant semantics (its results depends on the file in which its invoked, so that it always gets the right directory.)

Paul Hsieh
the thing is, I want the 'parseLastDir' to take place at compile-time (There's no reason it can't, since __FILE__ is predetermined). I was thinking perhaps something in the boost::mpl or some other hacky template metaprogramming inside a macro might let me do it..It's for a rather performance-critical application, and I don't want to waste time doing unnecessary string processing at runtime.
David Claridge
woops, forgot about markdownthat should be \__FILE__, not __FILE__
David Claridge
The problem is with compile time access to string literals - that is not possible now. It looks like we will have compile-time string processing in c++1x though.
Georg Fritzsche
Ok, but what you are asking for is restricted by the definition of the language itself. C++ does not contain a true metaprogramming language as you need (apparently LISP can do this no problem.) One way in which people have approached such problems in the past is to write their own pre-processor or use other existing ones.
Paul Hsieh
I was under the impression that C++ templates are Turing-complete. So C++ does have true metaprogramming.
David Claridge
Well, I think that its turing complete with respect to an input and output of types and source code. __FILE__ is not code or a type, but a specific textual substitution. Think of the __FILE__ bytes as outside of the "sandbox" of the C++ preprocessor in the same way that direct memory is outside the sandbox of Java (in both cases you can simulate it in code at run time or even access instances of it by was of the intrinsic mapping, but the real raw thing itself is not accessible.)
Paul Hsieh
+1  A: 

Hi Dave,

What you want is something similar to the unix

__BASE_FILE__

Take a look around http://theory.uwinnipeg.ca/localfiles/infofiles/gcc/cpp_13.html for it. I hope this helps.

EDIT: Attempt Two

How about using the #line preprocessor command. You can use it to change the filename variable too as you can see here: http://www.cppreference.com/wiki/preprocessor/line

Robert Massaioli
Close, but no cigar. That gives the filename/path as passed into g++, so it chops off some of the earlier parts of the path, but doesn't give me just the last dir as I want (since my code is in a bunch of sub-directories), so now I just get foo/bar instead of /home/davidc/some/path/to/some/code/foo/bar, close but unfortunately still the same problem.
David Claridge
Dammit, so close. I'm going to go keep looking.
Robert Massaioli
+1  A: 

Depending on your compiler/how your software is built, you can declare a macro to be the current or any path when you compile.

 gcc -D__DIR__=/usr/src/test/ test.c

I've never used the MS compiler but I know there is a similar option for ICC as well.

gcc manpage

Brian Gianforcaro
Thanks, but that's not what I'm after. I am compiling a large project with hundreds of files in different directories, the idea is that each file can #include this macro, and it will return the directory name corresponding to it's own source file location, I don't want to 'hard-code' the path to anywhere in particular.
David Claridge
oh and yes I'm using g++ on Linux
David Claridge
A: 

How about changing your makefile/build system so that for .../bar/file.cc the compilation line will include -D__DIR__ bar. It should be easier...

Oren S
+5  A: 

If you are using GNU make to build your project, then you might be able to do something like this:

%.o: %.cpp
    $(CC) $(CFLAGS) -D__DIR__="$(strip $(lastword $(subst /, , $(dir $(abspath $<)))))" -c $< -o $@

That has to be about the most God-awful thing that I have thought about doing in a Makefile in quite a while. I don't think that you will find a quick or clean way to do this within the confines of the compiler so I'd look for clever ways to inject the information into the compilation process.

Good luck.

D.Shawley
D'oh, you beat me by a minute -- I was doing pretty much the exact same thing. It doesn't quite work if the last directory has spaces in it, but otherwise it's a perfect solution. And believe me -- I've seen *far* worse monstrosities in Makefiles before.
Adam Rosenfield
@Adam: I just had to do some _fixups_ to get around version numbers starting with zeroes tonight. Going from 07.64 to 08.01 caused us lots of unnecessary grief.
D.Shawley
I'm using CMake, so I should be able to do this. Thanks!
David Claridge