Optimize library Arduino : undefined reference - arduino

The development for embedded system impose an other way to code.
In the goal to minimize size of my library named RF24Wave, I would adapt the structure of my main class.
The idea is to declare some functions only with the presence of certain #define during the inclusion of my library in main program.
The popular library, like MySensor use this way to minimize memory footprint.
So, I have two files for my library :
RF24Wave.h : header file which contain function declarations
#ifndef __RF24WAVE_H
#define __RF24WAVE_H
#include <arduino.h>
...
class RF24Wave
{
public:
/****** Common functions ******/
void begin();
#if !defined(WAVE_MASTER)
/****** Node functions ********/
void connect();
#else
/****** Master functions ******/
void printNetwork();
#endif
private:
bool synchronized = false;
}
RF24Wave.cpp: source file which contain function definitions
#include "RF24Wave.h"
void begin()
{
//Body of my function
}
#if !defined(WAVE_MASTER)
void connect()
{
//Body of my function
}
#else
void printNetwork()
{
//Body of my function
}
#endif
Secondly, I include this library in my main sketch named master.cpp, with #define WAVE_MASTER:
master.cpp: main sketch
#include <RF24.h>
#include <RF24Network.h>
#include <RF24Mesh.h>
#include <SPI.h>
#define WAVE_MASTER
#include <RF24Wave.h>
#include "master.h"
// Configure the chosen CE, CSN pins
RF24 radio(CE_PIN, CSN_PIN);
RF24Network network(radio);
RF24Mesh mesh(radio,network);
RF24Wave wave(network, mesh);
uint32_t displayTimer = 0;
void setup()
{
Serial.begin(115200);
wave.begin();
}
void loop()
{
wave.listen();
wave.printNetwork();
}
The goal is to include only master functions when #define WAVE_MASTER is defined in the main sketch.
However, during the compilation of my main sketch, I have a linking error
In function `main':
undefined reference to `RF24Wave::printNetwork()'
collect2: error: ld returned 1 exit status
*** [.pioenvs/uno/firmware.elf] Error 1
I compiled with PlaformIO Core 1.7.1 /Atom 1.13.0
Finally, the reason of this problem is the scope of #define.
The solution of this problem is added build flags to gcc-compiler !
If you use combo PlatformIO/Atom, you can add this line into this
config file platformio.ini :
build_flags = -D$NAME_DEFINE
In our case :
build_flags = -DWAVE_MASTER
After adding this line, the building seems work fine !
In addition, with this selective #define, my library has reduced footprint memory more than 10% !
Many thanks for your help.

If you add your library in the arduino IDE as it is described here it just consists in linking another project to your library functions. It's not a static library (see static and dynamic libraries). Then I think it's not necessary to worry about its size since the compiler will embed your library functions only if you use them.
Try opening any example (AnalogReadSerial), compile it. Then Sketch->Add a library->SPI. Compile it again, the size does not change. Try to call SPI.begin() in the setup function, the size increases. Add a call to SPI.setBitOrder(MSBFIRST);, the size increases again. Add another call to SPI.setBitOrder(MSBFIRST);, the size increases again, but not by the same amount since it contains only one setBitOrder definition and two calls to the setBitOrder function.
That's not exactly true for all libraries since some constructs could force the compiler to embed some code or allocate memory even if the variable is not used (see for instance volatile variables).
So regarding your size issue, you'd probably only need to use one #define MASTER, write the master code in setup and loop functions surrounded by #ifdef MASTER and the slave code surrounded by #else...#endif. The compiler will include the function definitions that both master or slave use.

So, with your answer, I found the solution !
The problem is the scope of #define. During the building, the first source code compiled is the main sketch ! So, it includes the correct #define WAVE_MASTER in RF24Wave.h of master.cpp. But, the compiler don't take this define into account of other source files. So, during the compilation of RF24Wave.cpp, #define WAVE_MASTER wasn't defined for this source file.
The solution consist to add an extra gcc-flag to define WAVE_MASTER for all source and header files.
With PlatformIO/Atom, it's possible in adding this line in config file platformio.ini
build_flags = -DWAVE_MASTER
Finally, your config file should look like this :
[env:uno]
platform = atmelavr
board = uno
framework = arduino
build_flags = -DWAVE_MASTER
With this solution, it is no longer necessary to add #define WAVE_MASTER in your header file, because this is the compiler which add it for you.
In addition, this optimization has been reduced more than 10% memory usage, because like this is a big class object, the compiler builded all functions. With selective define, the compiler will build only useful functions.

Related

CLion Arduino undefined reference

I have tried most of the suggestion regarding this issue to no avail.
I have created an Arduino project in CLion(version 2017.3.2) with Arduino plugin (version 1.2.3). I kept getting "undefined reference" during build.
My main Sample.ino file is:
#include <Arduino.h>
#include "Hello.h"
void setup() {
}
void loop() {
Hello::world();
}
and the Hello.h is simply:
#ifndef SAMPLE_HELLO_H
#define SAMPLE_HELLO_H
struct Hello {
static void world();
};
#endif //SAMPLE_HELLO_H
the Hello.cpp is
#include "Hello.h"
void Hello::world() {
}
and the CMakeLists.txt is:
cmake_minimum_required(VERSION 2.8.4)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/cmake/ArduinoToolchain.cmake)
set(PROJECT_NAME Sample)
project(${PROJECT_NAME})
set(${CMAKE_PROJECT_NAME}_SKETCH src/Sample.ino)
#include_directories(include)
include_directories(src)
#### Uncomment below additional settings as needed.
set(${CMAKE_PROJECT_NAME}_BOARD mega)
set(${CMAKE_PROJECT_NAME}_PORT /dev/ttyACM0)
set(mega.build.mcu atmega2560)
# set(mega.upload.protocol wiring)
set(mega.upload.speed 115200)
generate_arduino_firmware(${CMAKE_PROJECT_NAME})
All source files are under the folder src/,
Any suggestion to what have I missed?
I had the same problem and spent several hours to find a solution.
Arduino plugin uses arduino-cmake to build project. According to its documentation, to use generate_arduino_firmware command you should specify SKETCH or SRCS option.
If I define SKETCH option , I has no success to link additional files (hello.cpp).
So I try to use SRCS. Seems that if I define SKETCH and SRCS simultaneously, SRCS is be ignored. Another problem is when I specify src/sample.ino in SRCS option I have the same error.
So I do the following to compile the project successfully:
Renamed src/sample.ino into src/sample.cpp.
Commented out SKETCH and add SRCS option to list all source files:
set(${PROJECT_NAME}_SRCS src/sample.cpp src/hello.cpp)
Full CMakeList.txt is
cmake_minimum_required(VERSION 2.8.4)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/cmake/ArduinoToolchain.cmake)
set(CMAKE_CXX_STANDARD 14)
set(PROJECT_NAME Sample)
project(${PROJECT_NAME})
set(${PROJECT_NAME}_BOARD uno)
set(${PROJECT_NAME}_SRCS src/sample.cpp src/hello.cpp)
set(${PROJECT_NAME}_PROGRAMMER arduinoasisp)
set(${PROJECT_NAME}_PORT COM17)
set(${PROJECT_NAME}_AFLAGS -v)
generate_arduino_firmware(${PROJECT_NAME})
The Arduino support plugin uses arduino-cmake which has a bug causing your SRCS and HDRS to be erased when compiling a sketch.
You can read my bug report and proposed fix here. Basically you want to modify cmake/Platform/Arduino.cmake
Change line 1808 to avoid overwriting your sources
set(ALL_SRCS ${SKETCH_SOURCES})
set(ALL_SRCS ${ALL_SRCS} ${SKETCH_SOURCES})
Change line 1821 to recompile when a source changes
DEPENDS ${MAIN_SKETCH} ${SKETCH_SOURCES}
DEPENDS ${MAIN_SKETCH} ${ALL_SRCS}
I had that problem too.
Adding this to the CMakeLists made it work:
include_directories(${PROJECT_SOURCE_DIR})
file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
file(GLOB HDR_FILES ${PROJECT_SOURCE_DIR}/*.h)
set(PROJ_SRC ${SRC_FILES})
set(PROJ_HDR ${HDR_FILES})
generate_arduino_firmware(${CMAKE_PROJECT_NAME}
SRCS ${PROJ_SRC}
HDRS ${PROJ_HDR}
)
I'm not sure if that's the best solution but it worked in my case.

How to change header include guards in Rcpp interfaces?

I am lately trying to learn the (brilliant) Rcpp library. When I want to export some of my C++ code, afaik it is suggested to use sth like:
// [[Rcpp::interfaces(r, cpp)]]
// [[Rcpp::export(name=".mrwr_cpp")]]
Eigen::VectorXd mrwr_(const Eigen::VectorXd& p0,
const Eigen::MatrixXd& W,
const double r)
{
// impl
}
In this example // [[Rcpp::interfaces(r, cpp)]] would create a header file with the name of my R package (lets say the package is called diffusr). The content of the exported header (diffusr.h) would look like this:
// This file was generated by Rcpp::compileAttributes
// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
#ifndef __diffusr_h__
#define __diffusr_h__
#include "diffusr_RcppExports.h"
#endif // __diffusr_h__
Is there a way to change the header include guard autamatically? Two leading "_" might lead to undefined behaviour, if I am correct, and is reserved for the standard library (What are the rules about using an underscore in a C++ identifier?)
Best,
Simon
Briefly:
"You don't", as that is done in the code generators within Rcpp, so you would have to change Rcpp
Check the master branch on GitHub corresponding to the next release (in a week or two) as this was recently changed

warning undefined reference to arduino due in multiwii

I try to compile multiwii code on DUE https://github.com/HefnySco/MultiWii_DUE
I keep getting
C:\Users\MCA9A~1.HEF\AppData\Local\Temp\build4616066844745192383.tmp\EEPROM.cpp.o: In function eeprom_write_block(void*, void*, unsigned int)
C:\Users\MCA9A~1.HEF\AppData\Local\Temp\build4616066844745192383.tmp/Sensors.cpp:307: warning: undefined reference toWire'
I made a separate project to simulate the case and created file called class1.cpp and included Wire_DUE.h and then called it from the main project class Sample1.cpp and it worked using the very same Wire_DUE code.
Kindly advise
At last after 4 days I found the answer.
I used this in def.h
#if defined (__CM3_REV)
#define ARDUINO_DUE
#endif
and when I updated to this
#if defined (ARDUINO_ARCH_SAM)
#define ARDUINO_DUE
#endif
it works .... pls not that in both cases ARDUINO_DUE is defined .... but not sure what is the difference exactly as in both ways ARDUINO_DUE is active.... seems that in some .cpp files it is not active due to other declarations that conflict with __CM3_REV

How to include an already written library to a custom library in Arduino

I'm creating a new library to control the keypad and LCD together. Most of the code seems to compile, but when it reaches the line where I define the LiquidCristal variable, it says:
'LiquidCrystal' does not name a type when creating a custom library
This is the extract of content of my LCDKeypad.h
// Include types & constants of Wiring core API
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#include "WConstants.h"
#endif
// Include LCD library
#include <LiquidCrystal.h>
The error is in this line:
private:
LiquidCrystal lcd( 8, 9, 4, 5, 6, 7 ); // <<-- Error
Alright, I was reading a lot and I found a very interesting article about this subject:
Including multiple libraries
It says that the compiler does not search for libraries that are not included in the sketch file. The way to hack this is to force the compiler to link them before loading your libraries, including, in my case LiquidCrystal.h in the sketch.
Let's say my library "LCDkeypad" requires LiquidCrystal.
My main program (sketch) needs to include LiquidCrystal in order to load it for my library "LCDKeypad".
Now, one interesting thing is using forward declaration, so in my LCDKeypad.h I will declare
"Class LiquidCrystal" but not include the library. I will do it in LiquidCrystal.cpp and in the sketch.
I hope this is clear.
There are two ways of doing it
If you are writing your own code Just create header file .h extension and relevant c code as name_c.While adding into main program, you need to specify header file name in double quotes.
code:
#ifndef LCD_H
#define LCD_H
//Declaration of variable /functions
#endif
If you are trying to download from link. Then you need paste the code into D:\arduino\arduino\libraries
Error problem:
overlapping of multiple declaration of variable.
overlapping of library functions

Is there a way for a C binary code to figure out where it is stored? [duplicate]

Is there a platform-agnostic and filesystem-agnostic method to obtain the full path of the directory from where a program is running using C/C++? Not to be confused with the current working directory. (Please don't suggest libraries unless they're standard ones like clib or STL.)
(If there's no platform/filesystem-agnostic method, suggestions that work in Windows and Linux for specific filesystems are welcome too.)
Here's code to get the full path to the executing app:
Variable declarations:
char pBuf[256];
size_t len = sizeof(pBuf);
Windows:
int bytes = GetModuleFileName(NULL, pBuf, len);
return bytes ? bytes : -1;
Linux:
int bytes = MIN(readlink("/proc/self/exe", pBuf, len), len - 1);
if(bytes >= 0)
pBuf[bytes] = '\0';
return bytes;
If you fetch the current directory when your program first starts, then you effectively have the directory your program was started from. Store the value in a variable and refer to it later in your program. This is distinct from the directory that holds the current executable program file. It isn't necessarily the same directory; if someone runs the program from a command prompt, then the program is being run from the command prompt's current working directory even though the program file lives elsewhere.
getcwd is a POSIX function and supported out of the box by all POSIX compliant platforms. You would not have to do anything special (apart from incliding the right headers unistd.h on Unix and direct.h on windows).
Since you are creating a C program it will link with the default c run time library which is linked to by ALL processes in the system (specially crafted exceptions avoided) and it will include this function by default. The CRT is never considered an external library because that provides the basic standard compliant interface to the OS.
On windows getcwd function has been deprecated in favour of _getcwd. I think you could use it in this fashion.
#include <stdio.h> /* defines FILENAME_MAX */
#ifdef WINDOWS
#include <direct.h>
#define GetCurrentDir _getcwd
#else
#include <unistd.h>
#define GetCurrentDir getcwd
#endif
char cCurrentPath[FILENAME_MAX];
if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
{
return errno;
}
cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */
printf ("The current working directory is %s", cCurrentPath);
This is from the cplusplus forum
On windows:
#include <string>
#include <windows.h>
std::string getexepath()
{
char result[ MAX_PATH ];
return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
}
On Linux:
#include <string>
#include <limits.h>
#include <unistd.h>
std::string getexepath()
{
char result[ PATH_MAX ];
ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
return std::string( result, (count > 0) ? count : 0 );
}
On HP-UX:
#include <string>
#include <limits.h>
#define _PSTAT64
#include <sys/pstat.h>
#include <sys/types.h>
#include <unistd.h>
std::string getexepath()
{
char result[ PATH_MAX ];
struct pst_status ps;
if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0)
return std::string();
if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0)
return std::string();
return std::string( result );
}
If you want a standard way without libraries: No. The whole concept of a directory is not included in the standard.
If you agree that some (portable) dependency on a near-standard lib is okay: Use Boost's filesystem library and ask for the initial_path().
IMHO that's as close as you can get, with good karma (Boost is a well-established high quality set of libraries)
I know it is very late at the day to throw an answer at this one but I found that none of the answers were as useful to me as my own solution. A very simple way to get the path from your CWD to your bin folder is like this:
int main(int argc, char* argv[])
{
std::string argv_str(argv[0]);
std::string base = argv_str.substr(0, argv_str.find_last_of("/"));
}
You can now just use this as a base for your relative path. So for example I have this directory structure:
main
----> test
----> src
----> bin
and I want to compile my source code to bin and write a log to test I can just add this line to my code.
std::string pathToWrite = base + "/../test/test.log";
I have tried this approach on Linux using full path, alias etc. and it works just fine.
NOTE:
If you are on windows you should use a '\' as the file separator not '/'. You will have to escape this too for example:
std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));
I think this should work but haven't tested, so comment would be appreciated if it works or a fix if not.
Filesystem TS is now a standard ( and supported by gcc 5.3+ and clang 3.9+ ), so you can use current_path() function from it:
std::string path = std::experimental::filesystem::current_path();
In gcc (5.3+) to include Filesystem you need to use:
#include <experimental/filesystem>
and link your code with -lstdc++fs flag.
If you want to use Filesystem with Microsoft Visual Studio, then read this.
No, there's no standard way. I believe that the C/C++ standards don't even consider the existence of directories (or other file system organizations).
On Windows the GetModuleFileName() will return the full path to the executable file of the current process when the hModule parameter is set to NULL. I can't help with Linux.
Also you should clarify whether you want the current directory or the directory that the program image/executable resides. As it stands your question is a little ambiguous on this point.
On Windows the simplest way is to use the _get_pgmptr function in stdlib.h to get a pointer to a string which represents the absolute path to the executable, including the executables name.
char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
Maybe concatenate the current working directory with argv[0]? I'm not sure if that would work in Windows but it works in linux.
For example:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv) {
char the_path[256];
getcwd(the_path, 255);
strcat(the_path, "/");
strcat(the_path, argv[0]);
printf("%s\n", the_path);
return 0;
}
When run, it outputs:
jeremy#jeremy-desktop:~/Desktop$ ./test
/home/jeremy/Desktop/./test
For Win32 GetCurrentDirectory should do the trick.
You can not use argv[0] for that purpose, usually it does contain full path to the executable, but not nessesarily - process could be created with arbitrary value in the field.
Also mind you, the current directory and the directory with the executable are two different things, so getcwd() won't help you either.
On Windows use GetModuleFileName(), on Linux read /dev/proc/procID/.. files.
Just my two cents, but doesn't the following code portably work in C++17?
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main(int argc, char* argv[])
{
std::cout << "Path is " << fs::path(argv[0]).parent_path() << '\n';
}
Seems to work for me on Linux at least.
Based on the previous idea, I now have:
std::filesystem::path prepend_exe_path(const std::string& filename, const std::string& exe_path = "");
With implementation:
fs::path prepend_exe_path(const std::string& filename, const std::string& exe_path)
{
static auto exe_parent_path = fs::path(exe_path).parent_path();
return exe_parent_path / filename;
}
And initialization trick in main():
(void) prepend_exe_path("", argv[0]);
Thanks #Sam Redway for the argv[0] idea. And of course, I understand that C++17 was not around for many years when the OP asked the question.
Just to belatedly pile on here,...
there is no standard solution, because the languages are agnostic of underlying file systems, so as others have said, the concept of a directory based file system is outside the scope of the c / c++ languages.
on top of that, you want not the current working directory, but the directory the program is running in, which must take into account how the program got to where it is - ie was it spawned as a new process via a fork, etc. To get the directory a program is running in, as the solutions have demonstrated, requires that you get that information from the process control structures of the operating system in question, which is the only authority on this question. Thus, by definition, its an OS specific solution.
#include <windows.h>
using namespace std;
// The directory path returned by native GetCurrentDirectory() no end backslash
string getCurrentDirectoryOnWindows()
{
const unsigned long maxDir = 260;
char currentDir[maxDir];
GetCurrentDirectory(maxDir, currentDir);
return string(currentDir);
}
For Windows system at console you can use system(dir) command. And console gives you information about directory and etc. Read about the dir command at cmd. But for Unix-like systems, I don't know... If this command is run, read bash command. ls does not display directory...
Example:
int main()
{
system("dir");
system("pause"); //this wait for Enter-key-press;
return 0;
}
Works with starting from C++11, using experimental filesystem, and C++14-C++17 as well using official filesystem.
application.h:
#pragma once
//
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
//
#ifdef __cpp_lib_filesystem
#include <filesystem>
#else
#include <experimental/filesystem>
namespace std {
namespace filesystem = experimental::filesystem;
}
#endif
std::filesystem::path getexepath();
application.cpp:
#include "application.h"
#ifdef _WIN32
#include <windows.h> //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h> //readlink
#endif
std::filesystem::path getexepath()
{
#ifdef _WIN32
wchar_t path[MAX_PATH] = { 0 };
GetModuleFileNameW(NULL, path, MAX_PATH);
return path;
#else
char result[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
return std::string(result, (count > 0) ? count : 0);
#endif
}
For relative paths, here's what I did. I am aware of the age of this question, I simply want to contribute a simpler answer that works in the majority of cases:
Say you have a path like this:
"path/to/file/folder"
For some reason, Linux-built executables made in eclipse work fine with this. However, windows gets very confused if given a path like this to work with!
As stated above there are several ways to get the current path to the executable, but the easiest way I find works a charm in the majority of cases is appending this to the FRONT of your path:
"./path/to/file/folder"
Just adding "./" should get you sorted! :) Then you can start loading from whatever directory you wish, so long as it is with the executable itself.
EDIT: This won't work if you try to launch the executable from code::blocks if that's the development environment being used, as for some reason, code::blocks doesn't load stuff right... :D
EDIT2: Some new things I have found is that if you specify a static path like this one in your code (Assuming Example.data is something you need to load):
"resources/Example.data"
If you then launch your app from the actual directory (or in Windows, you make a shortcut, and set the working dir to your app dir) then it will work like that.
Keep this in mind when debugging issues related to missing resource/file paths. (Especially in IDEs that set the wrong working dir when launching a build exe from the IDE)
A library solution (although I know this was not asked for).
If you happen to use Qt:
QCoreApplication::applicationDirPath()
Path to the current .exe
#include <Windows.h>
std::wstring getexepathW()
{
wchar_t result[MAX_PATH];
return std::wstring(result, GetModuleFileNameW(NULL, result, MAX_PATH));
}
std::wcout << getexepathW() << std::endl;
// -------- OR --------
std::string getexepathA()
{
char result[MAX_PATH];
return std::string(result, GetModuleFileNameA(NULL, result, MAX_PATH));
}
std::cout << getexepathA() << std::endl;
This question was asked 15 years ago, so the existing answers are now incorrect. If you're using C++17 or greater, the solution is very straightforward today:
#include <filesystem>
std::cout << std::filesystem::current_path();
See cppreference.com for more information.
On POSIX platforms, you can use getcwd().
On Windows, you may use _getcwd(), as use of getcwd() has been deprecated.
For standard libraries, if Boost were standard enough for you, I would have suggested Boost::filesystem, but they seem to have removed path normalization from the proposal. You may have to wait until TR2 becomes readily available for a fully standard solution.
Boost Filesystem's initial_path() behaves like POSIX's getcwd(), and neither does what you want by itself, but appending argv[0] to either of them should do it.
You may note that the result is not always pretty--you may get things like /foo/bar/../../baz/a.out or /foo/bar//baz/a.out, but I believe that it always results in a valid path which names the executable (note that consecutive slashes in a path are collapsed to one).
I previously wrote a solution using envp (the third argument to main() which worked on Linux but didn't seem workable on Windows, so I'm essentially recommending the same solution as someone else did previously, but with the additional explanation of why it is actually correct even if the results are not pretty.
As Minok mentioned, there is no such functionality specified ini C standard or C++ standard. This is considered to be purely OS-specific feature and it is specified in POSIX standard, for example.
Thorsten79 has given good suggestion, it is Boost.Filesystem library. However, it may be inconvenient in case you don't want to have any link-time dependencies in binary form for your program.
A good alternative I would recommend is collection of 100% headers-only STLSoft C++ Libraries Matthew Wilson (author of must-read books about C++). There is portable facade PlatformSTL gives access to system-specific API: WinSTL for Windows and UnixSTL on Unix, so it is portable solution. All the system-specific elements are specified with use of traits and policies, so it is extensible framework. There is filesystem library provided, of course.
The linux bash command
which progname will report a path to program.
Even if one could issue the which command from within your program and direct the output to a tmp file and the program
subsequently reads that tmp file, it will not tell you if that program is the one executing. It only tells you where a program having that name is located.
What is required is to obtain your process id number, and to parse out the path to the name
In my program I want to know if the program was
executed from the user's bin directory or from another in the path
or from /usr/bin. /usr/bin would contain the supported version.
My feeling is that in Linux there is the one solution that is portable.
Use realpath() in stdlib.h like this:
char *working_dir_path = realpath(".", NULL);
The following worked well for me on macOS 10.15.7
brew install boost
main.cpp
#include <iostream>
#include <boost/filesystem.hpp>
int main(int argc, char* argv[]){
boost::filesystem::path p{argv[0]};
p = absolute(p).parent_path();
std::cout << p << std::endl;
return 0;
}
Compiling
g++ -Wall -std=c++11 -l boost_filesystem main.cpp

Resources