I work on a team project using a teensy and matlab, and to avoid version differences (e.g one person loads the teensy with version A, and the person now using it with matlab has version B of the code), I'd like to send a version string on pairing.
However, I want the version string to sit in a shared file between the matlab code and the teensy, and every time the program is loaded to the teensy, have it included on compilation as a constant.
Sort of like:
const string version = "<included file content>";
The matlab on its part can read it at runtime.
I thought of using a file whose contents are an assignment to a variable whose name is shared both by teensy and matlab, however I would prefer a more elegant solution if such exists, especially one that doesn't include executing code from an external file at runtime.
One way is just to have a simple setup like so:
version.inc:
"1.0.0rc1";
main.cpp:
const string version =
#include "version.inc"
...
Note that the newline between the = and the #include is in place to keep the compiler happy. Also, if you don't want to include the semicolon in the .inc file, you can do this:
main.cpp:
const string version =
#include "version.inc"
; // Put the semicolon on a newline, again to keep the compiler happy
EDIT: Instead of a .inc file, you can really have any file extension you desire. It's all up to taste
EDIT: If you really wanted to, you could omit the quotes from the .inc file, but that would lead to messy code like this:
version.inc:
STRINGIFY(
1.0.0rc1
);
main.cpp:
#define STRINGIFY(X) #X
const string version =
#include "version.inc"
...
EDIT:
As #Ôrel pointed out, you could handle the generation of a version.h or similar in your Makefile. Assuming you're running a *nix system, you could try a setup like this:
Makefile:
...
# "1.0.0rc1"; > version.h
echo \"`cat version.inc`\"\; > version.h
...
version.inc:
1.0.0rc1
main.cpp:
const string version =
#include "version.h"
Related
Just starting with this coming from a JS background.
I am looking into IoT development and wanted to set up my own repo without uploading the SSID and password of my personal WiFi.
Platform IO offers this platformio.ini as I understand to set build_flags.
build_flags =
-D SSID="MySSID"
I don't know how to access them from my CPP file though. I want to inject the value from the build flag SSID into my *.cpp file.
#define SSID
void loop()
{
Serial.println(SSID);
}
The above doesn't write anything to the serial monitor.
What am I doing wrong? The code does compile.
I know it's been two years, and you've probably moved on from this question. However, for anyone else - like myself - who happens across this from a Google search, here is the answer as I've found it:
According to PlatformIO's Dynamic Variables page, you correctly define the build variable so that it exists to C++ (as a macro); i.e., -DSSID="MySSID". What you missed, however, is that the values need to be quoted (and potentially escaped): -DSSID='"MySSID"' so that when you access the macro in C++ it is a const char * string and not an unknown symbol.
See the Warning at the bottom of the page, and note the quotes around the string:
Be careful with special characters in system environment variables on Unix systems, especially when they are used as the value for preprocessor directives. Symbols like $, &, ~, etc must be explicitly escaped, for example:
export WIFI_PASS='\"my\~p\&a\\\$\$\$\$word\"'
It wasn't initially obvious to me either, but it makes sense because the preprocessor will replace SSID with whatever you've defined and makes no assumptions about it or its type at all.
As #Azeem mentioned, you're redefining the SSID to an empty value. Using preprocessor like this, you must first check if the value exist and if not, assign it a default value.
Here is a simple C++ example:
#include <iostream>
#ifndef SSID
#define SSID "(SSID not defined)"
#endif
int main()
{
std::cout << "SSID value: " << SSID << std::endl;
return 0;
}
You can compile and run the code with:
g++ main.cpp -o main && ./main
As you see it prints (SSID not defined).
Now, compiling and running with the following:
g++ main.cpp -o main -DSSID='"Hello, World!"' && ./main
will output: SSID value: Hello, World!
If you want to learn more about preprocessor directives, cplusplus.com has very nice tutorial
Also, don't forget to start your Serial in void setup().
I have the following directory structure
my_func
- my_func_r.cpp
- my_func.c
- my_func.h
- my_func_test.c
- matrix/
- matrix.h
- matrix.c
The matrix directory contains some matrix structures in matrix.h and some initialisation, free, print etc. functions in matrix.c. The my_func.h file is something like
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "matrix/matrix.h"
... some structures and templates ...
The my_func.c file is then
#include "my_func.h"
... helper functions ...
int my_func(...) {
... my_func stuff ...
return 0;
}
The my_func_test.c is something like
#include "my_func.h"
int main() {
... some test ...
return 0;
}
With gcc/g++ I can run this fine with
gcc my_func_test.c my_func.c matrix/matrix.c -o test -lm
The final file my_func_r.cpp is an interface between the Rcpp structures and the structures used in my_func.c. It is currently something like
#include "my_func.h"
#include <Rcpp.h>
// [[Rcpp::export]]
int my_func_r(Rcpp::List x, ...) {
... convert inputs to structure recognised by my_func.h ...
... run my_func.c ...
... put returned objects back into one of the R structure ...
return 0;
}
The problem I have is if I now run
sourceCpp('my_func_r.cpp', verbose=TRUE, rebuild=TRUE)
It complains about missing symbols for functions located in matrix/matrix.c. A workaround is to simply paste all my header and source code from both the my_func and matrix files at the top of my_func_r.cpp.
This however feels a very unsatisfactory solution especially for code maintenance. What is the easiest way to accomplish what I am trying to do?
Quick ones:
This is not really particular to Rcpp per se
You are simply struggling with a more advanced / complicated src/ directory in an R build.
There is official documentation about this in Writing R Extensions, and the questions has come up here on SO before.
You could compile a libmatrix.a first in the subdirectory and link to that. This is doable via a simple src/Makevars but still discouraged. So read on.
But this is a self-inflicted wound. Just copy matrix.h and matrix.c into src/, adjust the include path, and you are done.
As always: Create a package. Don't use sourceCpp() on larger setup. It is not made for that,
I'm trying to compile Assimp with MinGW in Code::Blocks, but I get the following errors.
\assimp-3.3.1\assimp-3.3.1\code\StringComparison.h||In function 'int Assimp::ASSIMP_stricmp(const char*, const char*)':|
\assimp-3.3.1\assimp-3.3.1\code\StringComparison.h|144|error: '::strcasecmp' has not been declared|
\assimp-3.3.1\assimp-3.3.1\code\StringComparison.h||In function 'int Assimp::ASSIMP_strincmp(const char*, const char*, unsigned int)':|
\assimp-3.3.1\assimp-3.3.1\code\StringComparison.h|193|error: '::strncasecmp' has not been declared|
While searching I've found out that the two functions in question (strcasecmp and strncasecmp) are in fact declared in string.h which is included in the header of StringComparison.h. I've also managed to get strings.h, the file which they originally belong to, but including that didn't solved the issue either.
While searching this site I've found out that I'm not the only one struggling with this issue. Another solution I've found suggested to use define statements, because the functions might have a slightly different name, but that didn't helped either.
I just encountered this exact same problem, and this question came up during a Google search for the solution, so I'll document my dodgy solution here:
In the end I got it going just by making multiple small edits to the Assimp source code. Solving the string problem isn't enough to get it to work because it just fails later in the build. I'll list the edits I made below. I recommend making them one at a time and then rebuilding, just in case for whatever reason with your setup some of them aren't required. Note that you can't do model exporting with this solution because of the last edit (to Exporter.cpp) if you really need that you'll have to figure out another way to fix the link errors.
It's not a clean solution and it will probably be superceded by a future version of Assimp, at which point I will just delete it. This is for assimp-3.3.1, built with MinGW:
In StringComparison.h, edit the ASSIMP_stricmp function, commenting out everything except the else clause of the #ifdef:
/*#if (defined _MSC_VER)
return ::_stricmp(s1,s2);
#elif defined( __GNUC__ )
return ::strcasecmp(s1,s2);
#else*/
char c1, c2;
do {
c1 = tolower(*s1++);
c2 = tolower(*s2++);
}
while ( c1 && (c1 == c2) );
return c1 - c2;
//#endif
Do a similar thing in ASSIMP_strincmp.
Next, it throws up an error about ::_fullpath in DefaultIOSystem.cpp. My "fix" for this was just to use comment out everything other the fallback option in this function:
ai_assert(in && _out);
// char* ret;
//#if defined( _MSC_VER ) || defined( __MINGW32__ )
// ret = ::_fullpath( _out, in, PATHLIMIT );
//#else
// use realpath
// ret = realpath(in, _out);
//#endif
// if(!ret) {
// preserve the input path, maybe someone else is able to fix
// the path before it is accessed (e.g. our file system filter)
// DefaultLogger::get()->warn("Invalid path: "+std::string(in));
strcpy(_out,in);
// }
It also complains about snprintf being undefined. Edit StringUtils.h to change the following #define to add an underscore before snprintf:
# define ai_snprintf _snprintf
There's also an error about ::atof not being defined. You can fix this by adding
#include <cstdlib>
to StringUtils.h
This should get it building but there will be a link error in Exporter.cpp (this might be due to my specific CMake setttings because I disabled almost all model formats). I fixed it by commenting out the definition of gExporters and replacing it with this:
Exporter::ExportFormatEntry* gExporters = 0;
After this it built and ran fine. The library files are placed in the code folder. Place libassimp.dll.a in your lib build path and libassimp.dll in the path of your executable.
Of course, you can also get it going by using VisualStudio instead (I didn't because I couldn't be bothered installing it) or by building on Linux (I did this previously and it built fine first go, but I needed to do a Windows port).
I had some problems too but hopefully I was able to solve them. I know this is probably too late to help in particular but I hope someone on the Internet will find this useful. I compile using Code::Blocks 16.01 using gcc 5.3.0.
::strncasecmp not declared in this scope:
You have to include and remove the "::"
::_fullpath not declared in this scope:
I never had to perform the operation of finding a full path, so this one is the one I am the least sure of. But anyway, since I couldn't simply remove everything, I had to find the alternative. That is, using "GetFullPathName".
So, as suggested by MSDN, I included , , , .
I also replace the line :
ret = _fullpath( _out, in, PATHLIMIT );
by
ret = (char*)GetFullPathName(in, PATHLIMIT, _out, NULL);
Should work fine, full path is obtained and error checking is kept too.
vsnprintf not declared in this scope
Just add an underscore _ in front of the function name.
to_string is not a member of std::
I would have that this is the usual bug from using MinGW, but actually, Assimp contains a built-in alternative to std::to_string. You just have to remove the std:: part and it should roll.
Make sure to include in the files in which just removing std:: doesn't work.
test\CMakeFiles\gtest.dir\build.make|109|recipe for target 'test/gtest/src/gtest-stamp/gtest-build' failed| ?
It doesn't matter, you already have your working .dll in the "code" folder ;)
I was using Cygwin and encounter the same error, using strncmp and strcmp worked, guessing it is something to do with the libraries (ANSI C++) currently implemented for Cygwin or being used by your project. Not sure though, just wanted it to work for the moment...
Question should say it all.
Let's say there's a local file "mydefaultvalues.txt", separated from the main project. In the main project I want to have something like this:
char * defaultvalues = " ... "; // here should be the contents of mydefaultvalues.txt
And let the compiler swap " ... " with the actual contents of mydefaultvalues.txt. Can this be done? Is there like a compiler directive or something?
Not exactly, but you could do something like this:
defaults.h:
#define DEFAULT_VALUES "something something something"
code.c:
#include "defaults.h"
char *defaultvalues = DEFAULT_VALUES;
Where defaults.h could be generated, or otherwise created however you were planning to do it. The pre-processor can only do so much. Making your files in a form that it will understand will make things much easier.
The trick I did, on Linux, was to have in the Makefile this line:
defaultvalues.h: defaultvalues.txt
xxd -i defaultvalues.txt > defaultvalues.h
Then you could include:
#include "defaultvalues.h"
There is defined both unsigned char defaultvalues_txt[]; with the contents of the file, and unsigned int defaultvalues_txt_len; with the size of the file.
Note that defaultvalues_txt is not null-terminated, thus, not considered a C string. But since you also have the size, this should not be a problem.
EDIT:
A small variation would allow me to have a null-terminated string:
echo "char defaultvalues[] = { " `xxd -i < defaultvalues.txt` ", 0x00 };" > defaultvalues.h
Obviously will not work very well if the null character is present inside the file defaultvalues.txt, but that won't happen if it is plain text.
One way to achieve compile-time trickery like this is to write a simple script in some interpreted programming language(e.g. Python, Ruby or Perl will do great) which does a simple search and replace. Then just run the script before compiling.
Define your own #pramga XYZ directive which the script looks for and replaces it with the code that declares the variable with file contents in a string.
char * defaultvalues = ...
where ... contains the text string read from the given text file. Be sure to compensate for line length, new lines, string formatting characters and other special characters.
Edit: lvella beat me to it with far superior approach - embrace the tools your environment supplies you. In this case a tool which does string search and replace and feed a file to it.
Late answer I know but I don't think any of the current answers address what the OP is trying to accomplish although zxcdw came really close.
All any 7 year old has to do is load your program into a hex editor and hit CTRL-S. If the text is in your executable code (or vicinity) or application resource they can find it and edit it.
If you want to prevent the general public from changing a resource or static data just encrypt it, stuff it in a resource then decrypt it at runtime. Try DES for something small to start with.
I am trying to analyze c++ files using my custom made parser (written in c++). Before start parsing, I will like to get rid of all #define. I want the source file to be compilable after preprocessing. So best way will be to run C Preprocessor on the file.
cpp myfile.cpp temp.cpp
// or
g++ -E myfile.cpp > templ.cpp
[New suggestions are welcome.]
But due to this, the original lines and their line numbers will be lost as the file will contain all the header information also and I want to retain the line numbers. So the way out I have decided is,
Add a special symbol before
every line in the source file (except preprocessors)
Run the preprocessor
Extract the lines with that special
symbol and analyze them
For example, a typical source file will look like:
#include<iostream>
#include"xyz.h"
int x;
#define SOME value
/*
** This is a test file
*/
typedef char* cp;
void myFunc (int* i, ABC<int, X<double> > o)
{
//...
}
class B {
};
After adding symbol it will be like,
#include<iostream>
#include"xyz.h"
#3#int x;
#define SOME value
#5#/*
#6#** This is a test file
#7#*/
#8#typedef char* cp;
#9#
#10#void myFunc (int* i, ABC<int, X<double> > o)
#11#{
#12# //...
#13#}
#14#
#15#class B {
#16#};
Once all the macros and comments are removed, I will be left with thousands of line in which few hundred will be the original source code.
Is this approach correct ? Am I missing any corner case ?
You realize that g++ -E adds some of its own lines to its output which indicate line numbers in the original file? You'll find lines like
# 2 "foo.cc" 2
which indicate that you're looking at line 2 of file foo.cc . These lines are inserted whenever the regular sequence of lines is disrupted.
The imake program that used to come with X11 sources used a faintly similar system, marking the ends of lines with ## so that it could post-process them properly.
The output from gcc -E usually includes #line directives; you could perhaps use those instead of your symbols.