Two libraries have same file name

It could happen that two independent libraries have two identical file names.
The following example is like that.
The file names C.cpp and C.h appear in both libraries.
I would think that the compiler could figure out that they are distinct files because the paths are different.
But compiling gets this error on line 8:
error: 'lib2' has not been declared


Users don't always have the luxury of editing a library.
What is the usual way to make this compile if the user can not edit the library?

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <C.h>		//this gets error
//#include "lib2/C.h"	//this works

#include <D.h>		//this works

int main()
{
	lib2::C2 c;	//error: 'lib2' has not been declared
	c.fn1();
	c.fn2();

	lib1::D d;
	d.fn3();
}


lib1/C.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef lib1_C_h
#define lib1_C_h

#include <iostream>

namespace lib1
{
	class C
	{
		public:
			virtual void fn1();
	};
}
#endif 


lib1/C.cpp
1
2
3
4
5
6
#include "C.h"

void lib1::C::fn1()
{
	std::cout << " lib1::C::fn1()";
}


lib1/D.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef lib1_D_h
#define lib1_D_h

#include <iostream>

namespace lib1
{
	class D
	{
		public:
			virtual void fn3();
	};
}
#endi 


lib1/D.cpp
1
2
3
4
5
6
#include "D.h"

void lib1::D::fn3()
{
	std::cout << " lib1::D::fn3()";
}


lib2/C.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef lib2_C_h
#define lib2_C_h

#include <iostream>
#include "../lib1/C.h"

namespace lib2
{
	class C2 : public lib1::C
	{
		public:
			virtual void fn2();
	};
}
#endif 


lib2/C.cpp
1
2
3
4
5
6
#include "C.h"

void lib2::C2::fn2()
{
	std::cout << " lib2::C::fn2()";
}


output:
C:\Users\wolf\Documents\lib_namespace>make
g++ -Wall -Ilib1 -Ilib2 -c main.cpp -o obj/main.o
main.cpp: In function 'int main()':
main.cpp:12:2: error: 'lib2' has not been declared
  lib2::C2 c; //error: 'lib2' has not been declared
  ^
main.cpp:12:11: error: expected ';' before 'c'
  lib2::C2 c; //error: 'lib2' has not been declared
           ^
main.cpp:13:2: error: 'c' was not declared in this scope
  c.fn1();
  ^
make: *** [obj/main.o] Error 1

Thank you.
Well yeah, the compiler is going to give you an error because line 2 is commented out. Therefore the compiler has not seen the lib2 namespace.

Whether or not the compiler can figure out the files are different depends whether or not the include names are qualified.

For example, if I tell the compiler to search directories lib1 and lib2 and the include is simply #include "c.h" and c.h exists in both directories, the compile will use the one it finds first.

However, if the includes are qualified as in your example, the compiler will have no problem distinguishing the two files.
1
2
#include "lib1/c.h"
#include "lib2/c.h" 

Keep in mind that those file names are relative to the directory where your source is, so lib1 and lib2 must be directories under source directory. You can of course refer to a path relative to the parent directory or even use a fully qualified path name.

Also keep in mid that if c.h includes d.h and d.h exists in both directories, then the include of d.h (within c.h) must be similarly qualified.


Last edited on
Thank you AbstractinAnon. That makes sense.

What is "the parent directory"?
You can of course refer to a path relative to the parent directory
You have a couple of ways to organize your library directories.

1) project with child direcories.
c:\dev\myproj\lib1
c:\dev\myproj\lib2

In this case the includes would be
#include "lib1\c.h" // lib1 is subdirectory of myproj

2) Libraries are at the save level as myproj
c:\dev\myproj
c:\dev\lib1
c:\dev\lib2

In this case the includes would be relative to the parent directory:
#include ".\lib1\c.h" // note the . denoting the parent directory


Thank you for the explanations AbstractionAnon.

Interestingly, including both "lib1/C.h" and "lib2/C.h" does not confuse the compiler.
This runs:

main.cpp
1
2
3
4
5
6
7
8
9
#include "lib2/C.h"
#include "lib1/C.h"

int main()
{
	lib2::C2 c;
	c.fn1();
	c.fn2();
}


While this does not compile:

main.cpp
1
2
3
4
5
6
7
8
#include <C.h>

int main()
{
	lib2::C2 c;
	c.fn1();
	c.fn2();
}

the same paths -Ilib1 -Ilib2 are qualified in the compiler command line, but it gets an error:
g++ -Wall -Ilib1 -Ilib2 -c main.cpp -o obj/main.o
main.cpp: In function 'int main()':
main.cpp:14:2: error: 'lib2' has not been declared


Why does the first method work but not the second method?

I apologize for being so nit picky, it's just my way of trying to understand what is happening with the compiler.
Last edited on
As explained above, the compiler will search include directories in order, and choose the first "C.h" file it finds, which is incorrect.

You may not be able to modify the pre-compiled library code, but you always have the option to modify the header files.


Part of your confusion, I think, is that you are not clear about the separation between compile and link.

Sometime in the past, library files were compiled. They no longer need source code.

In the present, each one of your .cpp files needs to be compiled. It needs source code, including headers to tell the compiler how to compile your source to interface with the already-compiled libraries.

Once you have everything compiled to object files, plus the pre-compiled library code, the linker can now put it together to create an executable file.


So, the problem is that two header files conflict, since they use the same file name. When the original author of each library compiled his library, there was no conflict, because he did not have the other's library.

But you now need to deal with both. That's why your code must chose to include a more specific filename, such as stuff in the first example above.

Hope this helps.

the same paths -Ilib1 -Ilib2 are qualified in the compiler command line, but it gets an error:

g++ -Wall -Ilib1 -Ilib2 -c main.cpp -o obj/main.o


No, they are not "qualified". You're giving the compiler a list of places to search unqualified file names in order as I explained in the first example in my previous post. Since the include names are unqualified, the first c.h that is found will match. Since you specified lib1 before lib2 in the compiler directive, the compiler will look in lib1 first and will always find lib1/c.h.

When the include names are qualified (#include lib2/c.h), then compiler will only look there. There is no ambiguity and you don't need the -I options in the compiler directive.


OK, I see it now.

Including both "lib1/C.h" and "lib2/C.h" made the compiler look in both libraries.
Where as including just <C.h>, the compiler stops searching after finding the first C.h it finds.

So simple. Thank you for your patients.
Topic archived. No new replies allowed.