I am trying once more with arduino and create a small module just to gain fluency in the cpp sintaxe.
I am trying to create a utility module with a static method and using a header constant to decide if I have to print the debug messages or not.
But even using #ifndef to avoid duplications, I did not work
In the module DataMattersUtil I set the header constant DATA_MATTERS_DEBUG to false using #ifndef to avoid duplication. But when I execute this code, the message does not print on serial monitor because the constant is always false, even setting it to true on the module DataMattersRunner.ino that is the first to execute.
File: DataMattersRunner.ino
#define DATA_MATTERS_DEBUG true
#include <DataMattersRunner.h>
DataMattersRunner runner;
void setup() {
runner.setup();
}
void loop() { }
File: DataMattersRunner.cpp
#include <DataMattersUtil.h>
void DataMattersRunner::setup() {
DataMattersUtil::debug("Running ...");
}
File: DataMattersRunner.cpp
#include <DataMattersUtil.h>
void DataMattersRunner::setup() {
DataMattersUtil::debug("Running ...");
}
File: DataMattersUtil.h
#ifndef DATA_MATTERS_DEBUG
#define DATA_MATTERS_DEBUG false
#endif
#ifndef DataMattersUtil_h
#define DataMattersUtil_h
class DataMattersUtil {
public:
static void debug(String message);
};
void DataMattersUtil::debug(String message) {
if(DATA_MATTERS_DEBUG) {
Serial.println(message);
}
}
#endif
As DataMattersUtil.h is included in multiple compilation units you have to define DATA_MATTERS_DEBUG in all of them.
Instead of adding #define DATA_MATTERS_DEBUG before all #include <DataMattersUtil.h> you would use a compiler flag to do so. For gcc and clang it would be -DDATA_MATTERS_DEBUG
Your problem is that each cpp file is handled in a different compilation unit, and you've only defined DATA_MATTERS_DEBUG to true in DataMattersRunner.ino. Because your other files are in separate compilation units, they don't see the definition in DataMattersRunner.ino.
The best solution for you is probably to provide DATA_MATTERS_DEBUG using a compiler option. I don't have Arduino experience, but with gcc you can do something like this:
g++ -c DataMattersRunner.cpp -DDATA_MATTERS_DEBUG=true
Related
I'm working on an application that includes this library, let's call Snap.h.
I found that compilation fails if Snap.h is not the last on the includes statements. And on closer look, I find this code in a header file included by Snap.h
#define Try try {
#define Catch } catch (PExcept Except){ErrNotify(Except->GetMsgStr());}
#define CatchFull } catch (PExcept Except){ErrNotify(Except->GetStr());}
#define CatchAll } catch (...){}
Basically this lets try and catch blocks to be used as statements, like so
Try;
<some code>
Catch;
You can see how this is an issue, these generic macros collide with other libraries very easily.
Unfortunately this is tens of thousands of lines of very complicated code and the application I'm working on is built around this library. Its not easily changed.
Cpp is not my strong suit, is there a way to limit the effects of macros in an include?
I not a big fan of #undef things, because you never now what other bad stuff can slumber in that big header. I prefer isolating it in a "compilation barrier" i.e. only including it in a separate wrapper translation unit, which only redefines and forwards what you need. In the following example Snap.h redefines BULLSHIT to std::terminate, but as you can try, main.cpp can use the function in Snap.h without its version of BULLSHIT:
/*! #file main.cpp
*/
#include <iostream>
#define BULLSHIT
#include "snap_wrapper.h"
int main() {
BULLSHIT
std::cout << wrapper::nice_function() << "\n";
}
/*! #file Snap.h
*/
#ifndef UNTITLED5_SNAP_H
#define UNTITLED5_SNAP_H
#define BULLSHIT std::terminate();
int nice_function() {
return 42;
}
#endif //UNTITLED5_SNAP_H
/*! #snap_wrapper.h
*/
#ifndef UNTITLED5_SNAP_WRAPPER_H
#define UNTITLED5_SNAP_WRAPPER_H
namespace wrapper{
int nice_function();
}
#endif //UNTITLED5_SNAP_WRAPPER_H
/*! #file snap_wrapper.c
*/
#include "snap_wrapper.h"
#include "Snap.h"
namespace wrapper {
int nice_function() {
return ::nice_function();
}
}
What I'm trying to do is provide a library with some defaults set by #define directives in the library header. Those would determine what functions of the library code will be compiled with a given application. In case the application developer needs to add or remove library functions, it should "override" the library's defaults with new values without modifying the library. Besides modifying the library compiled code, those application header's #define values will, in turn, add or remove parts of the application code itself. This is for an embedded system, so even small memory savings are important.
Below are the 4 test files. I can't get it working if it's even possible to do this. Maybe the right question is: What's the correct order of #define / #undef inside the project files?
library.h:
#ifndef MY_LIBRARY_H
#define MY_LIBRARY_H
#include <stdio.h>
#define FUNCTION_1 true
#define FUNCTION_2 false
class Class {
public:
Class();
~Class();
#if FUNCTION_1
void Function_1(void);
#endif
#if FUNCTION_2
void Function_2(void);
#endif
};
#endif // MY_LIBRARY_H
library.cpp:
#include "library.h"
Class::Class() { /* Constructor */ };
Class::~Class() { /* Destructor */ };
#if FUNCTION_1
void Class::Function_1(void) {
printf("Hi, this is %s running ...\n\r", __func__);
}
#endif
#if FUNCTION_2
void Class::Function_2(void) {
printf("Hi, this is %s running ...\n\r", __func__);
}
#endif
tst-09.h
#ifndef TST_09_H
#define TST_09_H
#include <library.h>
#undef FUNCTION_2 // .....................................................
#define FUNCTION_2 true // THIS IS WHERE I'M TRYING TO OVERRIDE THE LIB DEFAULTS
#endif // TST_09_H
tst-09.cpp:
#include "tst-09.h"
int main(void) {
Class object;
#if FUNCTION_1
object.Function_1();
#endif
#if FUNCTION_2
object.Function_2();
#endif
}
Take advantage of the capabilities of your linker. If you want to exclude unused or unnecessary code from you binary, one way to do that is to put each function in its own source module. (Some compiler packages support Function Level Linking, where the linker can remove unreferenced functions.)
Trying to use macros the way you show in your question would need them to be defined on the command line (and the library rebuilt with any change).
I am using standard CPP to preprocess any C/CPP file.
I am using the below command for preprocessing:
cpp -idirafter <path_to_header_files> -imacros <sourcefile> <source_file> > <destination_file>
The above command is replacing all the macros with its corresponding implementations defined in header files.
If I want some specific MACROS containing a particular string (eg, ASSERT) should not replace by cpp preprocessor. ie, if any macro defined by the name of TC_ASSERT_EQ or TC_ASSERT_NEQ defined in some header files should not replace by preprocessor.
Is there any ways I can control this?
You can use predefined macros to work around this. You can pass different defines to cpp and gcc/g++ using -D parameters
For example your assertion header can look like my_assert.h:
#ifndef __my_assert_h__
#define __my_assert_h__
#if defined ASSERT_DEBUG
#define my_assert(expr) my_assert(expr) /* please dont touch my assertions */
#else
#define my_assert(expr) ((void)0U) /* Your assertion macro here */
#endif /* ASSERT_xxx */
#endif /* #ifndef __my_assert_h__ */
And your source files can be as before. For example test.c:
#include "my_assert.h"
#include <stdio.h>
void foo (int p) {
my_assert(p==1);
puts("Tralala\n");
}
int main (void) {
foo(1);
return 0;
}
With the above trick you can run
cpp -DASSERT_DEBUG test.c
While the compilation still works as before.
gcc test.c
I have used #pragma poison TC_ASSERT_EQ statements to pass the line without preprocessing.
Imagine I have two .hpp files:
#ifndef _DEF_FILE_1_
#define _DEF_FILE_1_
inline void some_function_1(){
/*do stuff*/
}
#endif
and
#ifndef _DEF_FILE_2_
#define _DEF_FILE_2_
#ifdef _DEF_FILE_1_
inline void some_function_2(){
/*do stuff using some_function_1()*/
}
#else
inline void some_function_2(){
/*do the same stuff without using some_function_1()*/
}
#endif
#endif
My problem arises when I don't know in which order the files are included, e.g:
in the main.cpp i can have something like :
#include "file1.hpp"
#include "file2.hpp"
int main(){
some_function_2();
/*will call the function that uses some_function_1()*/
}
or
#include "file2.hpp"
#include "file1.hpp"
int main(){
some_function_2();
/*will call the function that doesn't use some_function_1()*/
}
Is there a way to make sure that as soon as both file1.hpp and file2.hpp
are included, then some_function_2() will call some_function_1()?
PS: One solution would be to include file1.hpp in file2.hpp but I can't do
that because I developp a code that may or may not depend on some library
that the end-user may or may not have.
PPS: The only other solution I can think of (even if I don't know how to
achieve this) would be to "delete" the definition of some_method_2() when
file1.hpp is included and then reinclude file2.hpp.
I believe proper solution would be to rewrite some_function_2() using SFINAE mechanism and template instead of preprocessor tricks. That way instantiation will happen in cpp file where it would be known if some_function_1() exists and order of include will not matter.
Your users should know if they have "some library" or, you should have some way of determining if that library is present. So you could do something like:
In file2.hpp
#ifndef _DEF_FILE_2_
#define _DEF_FILE_2_
#ifdef _DEF_HAS_SOME_LIBRARY_
#include "file1.hpp"
inline void some_function_2(){
/*do stuff using some_function_1()*/
}
#else
inline void some_function_2(){
/*do the same stuff without using some_function_1()*/
}
#endif
#endif
Or if possible eliminate file1.hpp entirely, and put some_function_1() in the location of #include "file1.hpp" above.
Now main.cpp should only include file2.hpp.
// optionally #define _DEF_HAS_SOME_LIBRARY_
#include "file2.hpp"
int main(){
some_function_2();
/*will call the function that uses some_function_1()*/
}
though, a solution that avoids the preprocessor would be better in my opinion.
If you don't know whether the file exists and need to handle that, well, neither c nor c++ preprocessor handle file existence checks. This is one of the reasons behind configure tools.
You need to probe for this information beforehand, and set it before compiling. There many ways to do it. Usually a tool / script, creates some configure.h header with appropriate defines is created. E.g. containing such line #define FILE1_HPP_EXISTS 1.
Then you can always rely on presence of configure.h and it will provide information you need.
If your compiler allows it you might use the _has_include macro:
Just change you file2.hpp to:
#ifndef _DEF_FILE_2_
#define _DEF_FILE_2_
#if defined(__has_include) && __has_include("file1.hpp")
# include "file1.hpp"
inline void some_function_2() {
/*do stuff using some_function_1()*/
}
#else
inline void some_function_2() {
/*do the same stuff without using some_function_1()*/
}
#endif
#endif
But keep in mind that this is a compiler specific extension.
In my Eclipse C/C++ project there is this undefined reference error which doesn't go away, doesn't matter what I do. I already changed the link order, checked if all files are compiled and included, basically everything, which is recommended in the in the Internet, when facing this problem.
Here's my program:
[...] - means that there is more code, which doesn't relate.
menulib.h
[...]
void start_GUI( void );
[...]
start_GUI.c - Note this is a .c-File
#include "menulib.h"
void start_GUI( void )
{
[...]
}
coreInterface.h
#ifndef COREINTERFACE_H_
#define COREINTERFACE_H_
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
/** only include the Core when compiled for C++ */
#include "Core.h"
#endif /* #ifdef CORE */
#ifdef __cplusplus
extern "C" {
#endif
void init_GUI( Core* core);
#ifdef __cplusplus
}
#endif
#endif /* COREINTERFACE_H_ */
coreInterface.cpp - Note this is a .cpp-File
#include "coreInterface.h"
#include "menulib.h"
void init_GUI( Core* core)
{
gui_core = core;
start_GUI(); // <--- **error appears here** - calls a .c file
}
Here's the error in the makefile (the auto generated one from Eclipse):
g++ -L/home/PC/the_Project/menu_GUI -o "the_Project" [...] ./menu_GUI/coreInterface.o [...] ./menu_GUI/start_GUI.o [...] -lcurses
./menu_GUI/coreInterface.o: In function `init_GUI':
/home/PC/the_Project/Default/../menu_GUI/coreInterface.cpp:23: undefined reference to `start_GUI()'
I believe this is coming from merging the .c and .cpp files. Still I couldn't solve it. Has anyone an idea?
Kind Regards
The problem is that you share the menulib.h header between C and C++ without specifying to C++ compiler that the function start_GUI is defined in C. Use extern "C" in #ifdef not only for init_GUI, but also for start_GUI.
Working example:
#include "coreInterface.h"
extern "C" {
#include "menulib.h"
}
void init_GUI( Core* core)
{
gui_core = core;
start_GUI();
}