Makefile question

The follow code compiles from g++ command but gets an error from Make.
So the code is good but there is something wrong with my Makefile.

emuliate_Arduino\usb_api.h
1
2
3
4
5
6
7
8
9
10
11
#ifndef usb_api_h
#define usb_api_h
#include <iostream>
using namespace std;

class usb_keyboard_class
{
	public:
		void print(char const * const str);
};
#endif 

emuliate_Arduino\usb_api.cpp
1
2
3
4
5
6
7
#include <iostream>
#include "usb_api.h"

void usb_keyboard_class::print(char const * const str) { cout << str; }

// Preinstantiate Objects //////////////////////////////////////////////////////
usb_keyboard_class Keyboard;


keyboard\KE.h
1
2
3
4
5
6
7
8
9
#ifndef KE_h
#define KE_h

class KE
{
	public:
		void print(char const * const str);
};
#endif 

keyboard\KE.cpp
1
2
3
4
5
6
7
8
#include "KE.h"

//extern usb_keyboard_class Keyboard;

void KE::print(char const * const str)
{
	Keyboard.print(str); // error: 'Keyboard' was not declared in this scope
}

main.cpp
1
2
3
4
5
6
7
8
9
#include "emuliate_Arduino/usb_api.cpp"
#include "kybrd/KE.cpp"

KE ke;

int main()
{
	ke.print("print_cpp");
}


The code gets a compile error when I run this Makefile:
1
2
3
4
5
6
7
8
9
10
11
12
13
all: a.exe

a.exe: main.o Keyboard.o KE.o
	g++ -o $@ $^
	
main.o: main.cpp
	g++ -c $^

KE.o: kybrd/KE.cpp kybrd/KE.h
	g++ -c $^

Keyboard.o: emuliate_Arduino/usb_api.cpp emuliate_Arduino/usb_api.h
	g++ -c $^


kybrd/KE.cpp:7:2: error: 'Keyboard' was not declared in this scope

D:\wolf\Documents\teensy\demo_MinGW\keyboard>g++ main.cpp

D:\wolf\Documents\teensy\demo_MinGW\keyboard>a
print_cpp
D:\wolf\Documents\teensy\demo_MinGW\keyboard>make
g++ -c emuliate_Arduino/usb_api.cpp emuliate_Arduino/usb_api.h
g++ -c kybrd/KE.cpp kybrd/KE.h
kybrd/KE.cpp: In member function 'void KE::print(const char*)':
kybrd/KE.cpp:7:2: error: 'Keyboard' was not declared in this scope
  Keyboard.print(str); // error: 'Keyboard' was not declared in this scope
  ^
make: *** [KE.o] Error 1

D:\wolf\Documents\teensy\demo_MinGW\keyboard>

What is wrong with my Makefile?

Thank you.
Last edited on
"a.exe" has prerequisite "Keyboard.o"

but there is no rule to compile "Keyboard.o"


However, you are asking about the compiler error. In file "kybrd/KE.cpp" on line 7, you are trying to use identifier "Keyboard" -- but said identifier is unknown by compiler while compiling KE.cpp.

In fact, nothing will know anything about it, since it is a hidden object in "usb_api.cpp". (Frankly, I don't know why USB-anything files are defining a Keyboard class...)

If you wish to use the keyboard object, you must let other files know it exists. The simplest way is to declare it exists (but not cause it to exist) in your "usb_api.h" file:

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef usb_api_h
#define usb_api_h
#include <iostream>

class usb_keyboard_class
{
	public:
		void print(char const * const str);
};

// This says that 'Keyboard' exists
extern usb_keyboard_class Keyboard;
#endif  

Notice also how no header file should ever contain using directives. Read all about it here:
http://www.cplusplus.com/forum/general/13162/#msg63354

Hope this helps.
Last edited on
Thank you Duoas,
usb_api is where Arduino firmware defines defines usb_keyboard_class and instantiates the Keyboard object.
The usb_api posted here emulates Arduino's Keyboard.print() on a PC.

I made these changes based on your suggestions:
* removed directives from header files
* add usb_api.o rule to Makefile
* added "extern usb_keyboard_class Keyboard;" to usb_api.h
I don't understand the last one, since Keyboard is instantiated in usb_api.cpp

Unfortunately running make still gets the same error.

emuliate_Arduino\usb_api.h
1
2
3
4
5
6
7
8
9
10
11
12
13
// emuliate arduino-1.0.5\hardware\teensy\cores\usb_hid\usb_api.h
#ifndef usb_api_h
#define usb_api_h
#include <iostream>

class usb_keyboard_class
{
	public:
		void print(char const * const str);
};
// This says that 'Keyboard' exists
extern usb_keyboard_class Keyboard;
#endif 


emuliate_Arduino\usb_api.cpp
1
2
3
4
5
6
7
8
// emuliate arduino-1.0.5\hardware\teensy\cores\usb_hid\usb_api.cpp
#include "usb_api.h"
using namespace std;

void usb_keyboard_class::print(char const * const str) { cout << str; }

// Preinstantiate Objects //////////////////////////////////////////////////////
usb_keyboard_class Keyboard;


kybrd\KE.h
1
2
3
4
5
6
7
8
9
#ifndef KE_h
#define KE_h

class KE
{
	public:
		void print(char const * const str);
};
#endif 


kybrd\KE.cpp
1
2
3
4
5
6
#include "KE.h"

void KE::print(char const * const str)
{
	Keyboard.print(str); // error: 'Keyboard' was not declared in this scope
}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include "emuliate_Arduino/usb_api.cpp"
#include "kybrd/KE.cpp"


KE ke;

int main()
{
	ke.print("print_cpp");
}


Makefile:
1
2
3
4
5
6
7
8
9
10
11
12
13
all: a.exe

a.exe: main.o KE.o usb_api.o
	g++ -o $@ $^
	
main.o: main.cpp
	g++ -c $^

KE.o: kybrd/KE.cpp kybrd/KE.h
	g++ -c $^

usb_api.o: emuliate_Arduino/usb_api.cpp emuliate_Arduino/usb_api.h
	g++ -c $^


error: 'Keyboard' was not declared in this scope:

D:\wolf\Documents\teensy\demo_MinGW\keyboard>make
g++ -c main.cpp
g++ -c kybrd/KE.cpp kybrd/KE.h
kybrd/KE.cpp: In member function 'void KE::print(const char*)':
kybrd/KE.cpp:9:2: error: 'Keyboard' was not declared in this scope
  Keyboard.print(str); // error: 'Keyboard' was not declared in this scope
Last edited on
The modified usb_api.h tells the rest of the world about the Keyboard object, but the rest of the world also has to look to see it.

kybrd\KE.cpp
1
2
3
4
5
6
7
#include "KE.h"
#include "emuliate_Arduino\usb_api.h"

void KE::print(char const * const str)
{
	Keyboard.print(str); // error: 'Keyboard' was not declared in this scope
}


Makefile (snippet)
1
2
KE.o: kybrd/KE.cpp kybrd/KE.h emuliate_Arduino/usb_api.h
	g++ -c $^

Hope this helps.
Thank you Duoas,

I made these Makefile changes based on your advice:
* added "emuliate_Arduino/usb_api.cpp emuliate_Arduino/usb_api.h" to the KE.o rule
* removed the usb_api.o rule

Makefile:
1
2
3
4
5
6
7
8
9
10
all: a.exe

a.exe: main.o
	g++ -o $@ $^
	
main.o: main.cpp
	g++ -c $^

KE.o: kybrd/KE.cpp kybrd/KE.h emuliate_Arduino/usb_api.cpp emuliate_Arduino/usb_api.h
	g++ -c $^


Running Make got a bunch of multiple definitions:
D:\wolf\Documents\teensy\demo_MinGW\keyboard>make
g++ -o a.exe main.o KE.o
KE.o:KE.cpp:(.text+0x0): multiple definition of `usb_keyboard_class::print(char
const*)'
main.o:main.cpp:(.text+0x0): first defined here
KE.o:KE.cpp:(.text+0x20): multiple definition of `KE::print(char const*)'
main.o:main.cpp:(.text+0x20): first defined here
KE.o:KE.cpp:(.bss+0x0): multiple definition of `Keyboard'
main.o:main.cpp:(.bss+0x0): first defined here
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: main.o: ba
d reloc address 0x0 in section `.ctors'
collect2.exe: error: ld returned 1 exit status
make: *** [a.exe] Error 1

Where are the multiple definitions coming from?
I have header guards in all the header files.

This Makefile compiled:
1
2
3
4
5
6
7
all: a.exe

a.exe: main.o
	g++ -o $@ $^
	
main.o: main.cpp
	g++ -c $^

Last edited on
I don't know know why you removed the usb_api.o rule... You need that for the Keyboard object, right?

If you instead try to include the .cpp file then you'll have the multiple definition problems
Duoas,

I removed the usb_api.o rule because the files where incorporated in the KE.o rule.
Anyway, the following code and Makefile work, with or without the KE.o rule.

Thank you for your patients. I have a better understanding of include directives and linker dependencies than before.

emuliate_Arduino\usb_api.h
1
2
3
4
5
6
7
8
9
10
11
12
// emuliate arduino-1.0.5\hardware\teensy\cores\usb_hid\usb_api.h
#ifndef usb_api_h
#define usb_api_h
#include <iostream>

class usb_keyboard_class
{
	public:
		void print(char const * const str);
};
extern usb_keyboard_class Keyboard;
#endif 


emuliate_Arduino\usb_api.cpp
1
2
3
4
5
6
7
8
// emuliate arduino-1.0.5\hardware\teensy\cores\usb_hid\usb_api.cpp
#include "usb_api.h"
using namespace std;

void usb_keyboard_class::print(char const * const str) { cout << str; }

// Preinstantiate Objects ////////////////////////////////////////////
usb_keyboard_class Keyboard;


kybrd\KE.h
1
2
3
4
5
6
7
8
9
10
#ifndef KE_h
#define KE_h
#include "../emuliate_Arduino/usb_api.h"

class KE
{
	public:
		void print(char const * const str);
};
#endif 


kybrd\KE.cpp
1
2
3
4
5
6
#include "KE.h"

void KE::print(char const * const str)
{
	Keyboard.print(str);
}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include "kybrd/KE.h"
#include "emuliate_Arduino/usb_api.h"

KE ke;

int main()
{
	ke.print("ke_cpp ");
	Keyboard.print("main_cpp ");
}


Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
all: a.exe

a.exe: main.o KE.o usb_api.o
	g++ -o $@ $^

main.o: main.cpp
	g++ -c $^

KE.o: kybrd/KE.cpp kybrd/KE.h emuliate_Arduino/usb_api.cpp emuliate_Arduino/usb_api.h
	g++ -c $^

usb_api.o: emuliate_Arduino/usb_api.cpp emuliate_Arduino/usb_api.h
	g++ -c $^


output:
D:\wolf\Documents\teensy\demo_MinGW\keyboard>a
ke_cpp main_cpp
Maybe I am reading this wrong, but it seems like there is confusion about what a makefile is. I say this because you are blaming compile errors upon make errors.

Edit: It also seems like you solved your problem...

A makefile compiles your code based on rules, which look like this:
1
2
target : prerequisites
  recipe


Make knows how to use g++ to construct a .o from a .cpp. The following example works:

function.h
1
2
3
4
5
6
#ifndef FUNCTION_H
#define FUNCTION_H

void function( void );

#endif 

function.cpp
1
2
3
4
5
6
7
#include "function.h"
#include <iostream>

void function( void )
{
  std::cout << "hello\n";
}

main.cpp
1
2
3
4
5
6
7
#include "function.h"

int main( void )
{
  function();
  return 0;
}

makefile
1
2
3
program: main.o function.o
  $(CXX) -o $@ $^


In short, program requires main.o and function.o, which make can use implicit rules to create.

The problem with this is that changes you make to function.h will not require you to rebuild. You can fix this by telling make that main.o and function.o require function.h
1
2
3
4
5
program: main.o function.o
        $(CXX) -o $@ $^

main.o: function.h
function.o: function.h


now you can do:
$ make && touch function.h && make
and the program will build twice.

In no way does adding the prerequisite of function.h to the objects in the makefile mean that you do no need to include function.h in main.cpp or function.cpp.

In short, with that last makefile you wrote, all you need is this:
1
2
3
4
all: a.exe

a.exe: main.o KE.o usb_api.o
	g++ -o $@ $^


Any problems you have with this are because your code isn't written right.

Edit:
As a side, the implicit rule that make creates is something like this ( from a cpp file):
$(CXX) $(CXXFLAGS) -c -o thing.o thing.cpp

As such, your makefile could look like this if you wanted to get better warnings:
1
2
3
4
5
CXXFLAGS= -Wall
all: a.exe

a.exe: main.o KE.o usb_api.o
	$(CXX) -o $@ $^


And the implicit rules will pick up -Wall as a compile flag
Last edited on
Don't #include cpp files.
Your directory structure and that global object are making life difficult for you.

Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
all: a.exe

a.exe: main.o usb_api.o KE.o
	g++ $^

main.o: main.cpp emuliate_Arduino/usb_api.h kybrd/KE.h
	g++ -c $^

KE.o: kybrd/KE.cpp kybrd/KE.h emuliate_Arduino/usb_api.h
	g++ -c $^

usb_api.o: emuliate_Arduino/usb_api.cpp emuliate_Arduino/usb_api.h
	g++ -c $^

main.cpp
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include "emuliate_Arduino/usb_api.h"
#include "kybrd/KE.h"

KE ke;

int main()
{
	ke.print("print_cpp");
}

kybrd/KE.h
1
2
3
4
5
6
7
8
9
#ifndef KE_h
#define KE_h

class KE
{
	public:
		void print(char const * const str);
};
#endif  

kybrd/KE.cpp
1
2
3
4
5
6
7
#include "KE.h"
#include "../emuliate_Arduino/usb_api.h"

void KE::print(char const * const str)
{
	Keyboard.print(str); // error: 'Keyboard' was not declared in this scope
}

emuliate_Arduino/usb_api.h
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef usb_api_h
#define usb_api_h
#include <iostream>

class usb_keyboard_class
{
	public:
		void print(char const * const str);
};

// This says that 'Keyboard' exists
extern usb_keyboard_class Keyboard;
#endif   

emuliate_Arduino/usb_api.cpp
1
2
3
4
5
6
7
#include <iostream>
#include "usb_api.h"

void usb_keyboard_class::print(char const * const str) { std::cout << str; }

// Preinstantiate Objects //////////////////////////////////////////////////////
usb_keyboard_class Keyboard;

This will compile cleanly.

However, I think you ought to spend some more time reading about multiple files in a project. Don't skim; take the time to peruse.

Good luck!
You can use VPATH, which tells make where it should look for prerequisites
VPATH=emuliate_Arduino:kybrd // note the colon as separator
Last edited on
...but you still have to list the prerequisites; make will not figure them out for you. The VPATH is just a convenience to avoid having to type in directory names.

For OPs makefile, I don't think it is an issue.

(A bigger issue might be OP's directory structure and code organization.)

[edit] ...and it is GNU-specific, AFAIK.
Last edited on
...and it is GNU-specific, AFAIK.

hmm, I think you're right about that.
Topic archived. No new replies allowed.