Hi I get a linking error when compiling my program with the gcc compiler on cygwin. The first picture is a simple sample program from the boost filesystem libraries tutorial page where I have included filesystem.hpp in the boost folder. Beneath that is the picture of my linker error when I try to compile with the following command:
g++ -I C:/Users/Ejer/Desktop/c++Dep/boost_1_77_0 -I C:/Users/Ejer/Desktop/c++Dep/eigen-3.4.0 -L C:/Users/Ejer/Desktop/c++Dep/boost_1_77_0/stage/lib test.cpp -o ser
Here I try to compile my program test.cpp with the eigen and boost libraries and set the includer path that they tell me to set as the path after I have built the library with b2.exe. I have also linked to the lib files for boost. I have also tried linking to the different filesystem lib files specifically. Thanks in advance
#include <iostream>
#include <boost/filesystem.hpp>
using std::cout;
using namespace boost::filesystem;
int main(int argc, char* argv[])
{
if (argc < 2)
{
cout << "Usage: tut3 path\n";
return 1;
}
path p (argv[1]);
try
{
if (exists(p))
{
if (is_regular_file(p))
cout << p << " size is " << file_size(p) << '\n';
else if (is_directory(p))
{
cout << p << " is a directory containing:\n";
for (directory_entry& x : directory_iterator(p))
cout << " " << x.path() << '\n';
}
else
cout << p << " exists, but is not a regular file or directory\n";
}
else
cout << p << " does not exist\n";
}
catch (const filesystem_error& ex)
{
cout << ex.what() << '\n';
}
return 0;
}
I get a linking error when compiling my program
No, you don't. You are getting a linking error when linking your program, not when compiling it.
The reason: you didn't supply the library (-L C:/Users/.... tells the linker where to search for libraries; not which libraries to link). Your command line should look something like:
g++ -I ... -L ... test1.cpp -o ser -lboost_filesystem
Related
I'm trying a very simple exmaple to create a shared library and link to it. The shared library is as follows:
#ifndef ARDUGRAB_H_
#define ARDUGRAB_H_
#include <iostream>
using namespace std;
namespace ArduGrabLibrary{
class ArduGrab{
public:
ArduGrab();
virtual void initCamera();
virtual void setSim(bool sim);
virtual void setDebug(bool debug);
private:
bool debug = false;
bool sim = false;
};
}
Then the source code file is just as simple:
#include "ardugrab.h"
namespace ArduGrabLibrary
{
ArduGrab::ArduGrab(){
std::cout << "IMX298 Constructor" << std::endl;
}
void ArduGrab::initCamera(){
if (this->debug){
cout << "init camera" << std::endl;
}
}
void ArduGrab::setSim(bool sim){
this->sim = sim;
if (this->debug){
cout << "set sim to " << std::boolalpha << this->sim << std::endl;
}
}
void ArduGrab::setDebug(bool debug){
this->debug = debug;
if (this->debug){
cout << "set debug to " << std::boolalpha << this->sim << std::endl;
}
}
}
I'm then compiling that into a shared library with:
g++ -fPIC -shared -o ardugrab.so ardugrab.cpp
All good, we get an ardgrab.so library so to test it, with the following code in teh same directory as the .so and .h files from above:
#include "ardugrab.h"
using namespace ArduGrabLibrary;
int main() {
std::cout << "starting program" << std::endl;
ArduGrab* ardu = new ArduGrab();
ardu->setDebug(true);
//imx298->setSim(true);
//imx298->initCamera();
return 0;
}
So now we need to compile this into an executable with:
g++ -L. -lardugrab -o testardugrab testardugrab.cpp
This however fails to find the ardugrab.so file, the follow error message appears:
pi#raspberrypi:~/ArduMipiGrab $ g++ -L. -lardugrab -o testardugrab testardugrab.cpp
/usr/bin/ld: cannot find -lardugrab
collect2: error: ld returned 1 exit status
I've tried setting LD_LIBRARY_PATH to . export LD_LIBRARY_PATH=. but still nothing.
As you can see I'm a bit new with compiling c++, can someone please advise me as to what I'm doing wrong?
Thanks.
Reagrds,
Neil
This is becuase you are using the -l flag.
When you use this flag (Rather than specify a library specifically) it assumes a certain naming convention.
-lX
The linker assumes the file name is
libX.so (or libX.a)
So the commands you want are:
> g++ -fPIC -shared -o libardugrab.so ardugrab.cpp
> # ^^^
> g++ -L. -lardugrab -o testardugrab testardugrab.cpp
Note: The environment variable LD_LIBRARY_PATH is used at runtime when the standard library tries to find and load required shared libraries. I.E. it is not used during compilation to find shared libraries to link with.
I am trying to run a cpp program on raspberry pi 3 b+ (from 'pi' user) but when I try to open a file with 'fstream' library it doesn't work.
I am using the following code (from main):
std::ios::sync_with_stdio(false);
std::string path = "/NbData";
std::ofstream nbData(path);
if (!nbData) {
std::cout << "Error during process...";
return 0;
}
nbData.seekp(std::ios::beg);
The program always fails there and stops because no file is created (I don't get a fatal error but the test fails and it outputs 'Error during process' which means no file was created).
I am compiling with the following command (there are no issues when I compile):
g++ -std=c++0x nbFinder.cpp -o nbFinder
I have already tried my program on Xcode and everything worked perfectly...
The problem is your path. You must put the file, you are using just the path and if the path do not exist will throw an error. In your case you just using std::string path = "/NbData";, that is you path not your file.
To be able to open your file you need make sure your path exist. Try use the code bellow, he will check if the path exist case not will create and then try to open your file.
#include <iostream>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
int main() {
std::ios::sync_with_stdio(false);
std::string path = "./test_dir/";
std::string file = "test.txt";
// Will check if thie file exist, if not will creat
struct stat info;
if (stat(path.c_str(), &info) != 0) {
std::cout << "cannot access " << path << std::endl;
system(("mkdir " + path).c_str());
} else if(info.st_mode & S_IFDIR) {
std::cout << "is a directory" << path << std::endl;
} else {
std::cout << "is no directory" << path << std::endl;
system(("mkdir " + path).c_str());
}
std::ofstream nbData(path + file);
if (!nbData) {
std::cout << "Error during process...";
return 0;
}
nbData.seekp(std::ios::beg);
return 0;
}
Here is a piece of code which is an example from cpp-netlib
#include <boost/network/protocol/http/server.hpp>
#include <string>
#include <iostream>
namespace http = boost::network::http;
struct hello_world;
typedef http::server<hello_world> server;
struct hello_world {
void operator() (server::request const &request,
server::response &response) {
std::string ip = source(request);
response = server::response::stock_reply(
server::response::ok, std::string("Hello, ") + ip + "!");
}
};
int
main(int argc, char * argv[]) {
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " address port" << std::endl;
return 1;
}
try {
hello_world handler;
server server_(argv[1], argv[2], handler);
server_.run();
}
catch (std::exception &e) {
std::cerr << e.what() << std::endl;
return 1;
}
return 0;
}
But on compiling that is g++ main.cpp -o socke.exe -lboost_system I get the following errors
main.cpp:1:50: error: boost/network/protocol/http/server.hpp: No such file or directory
main.cpp:5: error: âboostâ has not been declared
I have installed the cpnet-lib libraries and cmake for build them. I cant get to understand why couldnt the compiler find the libraries.
You didn't specify include path where Boost and cpp-netlib headers are located. The first error line tells which header is missing. Assuming your Boost headers are installed under /a/my_boost (i.e. there is a /a/my_boost/boost subdirectory with headers) and cpp-netlib under /a/my_cpp-netlib, you need to add -I command line options for your compiler:
g++ main.cpp -o socke.exe -I/a/my_boost -I/a/my_cpp-netlib -lboost_system
If you're using a graphical IDE or a build system, there should be an option in the project settings to add include directories.
I am new to C++ and I am trying to do a few things with my code. I have been researching on how to do them but haven't been able to get my head around it and have been fairly unsuccessful.
bool Copy(char filenamein[], char filenameout[]);
int main(int argc, char **argv)
{
if (argc !=3) {
cerr << "Usage: " << argv[0] << " <input filename> <output filename>" << endl;
int keypress; cin >> keypress;
return -1;
}
if (Copy(argv[1], argv[2]))
cout << "Copy completed" << endl;
else
cout << "Copy failed!" << endl;
system("pause");
return 0;
}
bool Copy(char filenamein[], char filenameout[])
{
ifstream fin(filenamein);
if(fin.is_open())
{
ofstream fout(filenameout);
char c;
while(fin.get(c))
{
fout.put(c);
}
fout.close();
fin.close();
return true;
}
return false;
}
This code already creates 2 text files, input.txt and output.txt. Both files also contains the same items/characters.
What I'm trying to do if checking if the input.txt file already exists before trying to copy it.
I am also wanting to check both files to make sure they are the same as well as checking the file sizes are equal.
How do I go about on doing this?
For general filesystem operations there's Boost Filesystem.
http://www.boost.org/doc/libs/1_57_0/libs/filesystem/doc/index.htm
To compare files you can calculate hashes and compare the hashes. For two files it would be just as efficient to compare them character by character but for more than two files comparing hashes wins.
For this there's Crypto++.
http://www.cryptopp.com/
Example of using the two libraries to solve the 3 problems in the question.
// C++ standard library
#include <iostream>
// Boost
#include <boost/filesystem.hpp>
// Crypto++
#include <cryptopp/sha.h>
#include <cryptopp/hex.h>
#include <cryptopp/files.h>
using std::string;
const string file_hash(const boost::filesystem::path &file);
int main( int argc, char** argv) {
if (argc != 3)
{
std::cout << "Usage: " << argv[0] << "filepath1 filepath2\n";
return 1;
}
const string filename1(argv[1]);
const string filename2(argv[2]);
std::cout << "filename 1: " << filename1 << std::endl;
std::cout << "filename 2: " << filename2 << std::endl;
// file existence
const bool file_exists1 = boost::filesystem::exists(filename1);
const bool file_exists2 = boost::filesystem::exists(filename2);
std::cout << "file 1 exists: " << std::boolalpha << file_exists1 << std::endl;
std::cout << "file 2 exists: " << std::boolalpha << file_exists2 << std::endl;
if (!file_exists1 || !file_exists2)
return EXIT_SUCCESS;
// file size
const boost::filesystem::path file_path1(filename1);
const boost::filesystem::path file_path2(filename2);
const uintmax_t file_size1 = boost::filesystem::file_size(file_path1);
const uintmax_t file_size2 = boost::filesystem::file_size(file_path2);
std::cout << "file 1 size: " << std::boolalpha << file_size1 << std::endl;
std::cout << "file 2 size: " << std::boolalpha << file_size2 << std::endl;
// comparing files
const string hash1 = file_hash(file_path1);
const string hash2 = file_hash(file_path2);
std::cout << "hash1: " << hash1 << std::endl;
std::cout << "hash2: " << hash2 << std::endl;
const bool same_file = hash1 == hash2;
std::cout << "same file: " << same_file << std::endl;
}
const string file_hash(const boost::filesystem::path& file)
{
string result;
CryptoPP::SHA1 hash;
CryptoPP::FileSource(file.string().c_str(),true,
new CryptoPP::HashFilter(hash, new CryptoPP::HexEncoder(
new CryptoPP::StringSink(result), true)));
return result;
}
Compilation on my laptop (the directories will of course be specific to wherever you have the headers and libraries but these are how homebrew installs them on OS X):
clang++ -I/usr/local/include -L/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem demo.cpp -o demo
Example usage:
$ ./demo demo.cpp demo.cpp
filename 1: demo.cpp
filename 2: demo.cpp
file 1 exists: true
file 2 exists: true
file 1 size: 2084
file 2 size: 2084
hash1: 57E2E81D359C01DA02CB31621C9565DF0BCA056E
hash2: 57E2E81D359C01DA02CB31621C9565DF0BCA056E
same file: true
$ ./demo demo.cpp Makefile
filename 1: demo.cpp
filename 2: Makefile
file 1 exists: true
file 2 exists: true
file 1 size: 2084
file 2 size: 115
hash1: 57E2E81D359C01DA02CB31621C9565DF0BCA056E
hash2: 02676BFDF25FEA9E3A4D099B16032F23C469E70C
same file: false
Boost Filesystem will throw exceptions if you try to do stuff like get the size of a file that doesn't exist. You should be prepared to catch those exceptions so you don't need to explicitly test for file existence since you should have a catch block anyway. (If all you want to know is if a file exists but you don't want to do stuff with the file then it makes sense to test for existence explicitly.)
This is how I would go about doing these things in practice. If what you're asking is how these things would be done without libraries then you can check if a file exists by using the C or C++ standard library to try and open a file and check if you succeeded. For checking file size, you can open a file, you can seek to the end and compare the position to the beginning of the file.
However, it's preferable to rely on operating system support to interact with filesystems in general.
https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek%28%29+and+ftell%28%29+to+compute+the+size+of+a+regular+file
fstat() for example is specific to Unix and Unix-like systems and returns a struct containing file size data but on Microsoft systems you use GetFileSizeEx() to get a file size. Because of this, if you want a portable solution then you have to use libraries that interact with the various operating systems for you and present a consistent API across operating systems.
Comparing files using only standard library support can be done by either implementing hashing functions or comparing files character by character.
Look at fstat, it will tell you the file size (or return an error if it does not exist).
You could also force the last update date of the copied file to be the same as the source file, so that if the source file changes but keeps the same size you will notice it (look at futimes to do so).
I've got a pretty basic console program here, to determine if a folder or file exists or not using stat:
#include <iostream>
#include <sys/stat.h>
using namespace std;
int main() {
char path[] = "myfolder/";
struct stat status;
if(stat(path,&status)==0) { cout << "Folder found." << endl; }
else { cout << "Can't find folder." << endl; } //Doesn't exist
cin.get();
return 0;
}
I have also tried the access version:
#include <iostream>
#include <io.h>
using namespace std;
int main() {
char path[] = "myfolder/";
if(access(path,0)==0) { cout << "Folder found." << endl; }
else { cout << "Can't find folder." << endl; } //Doesn't exist
cin.get();
return 0;
}
Neither of them find my folder (which is right there in the same directory as the program). These worked on my last compiler (the default one with DevCpp). I switched to CodeBlocks and am compiling with Gnu GCC now, if that helps. I'm sure it's a quick fix - can someone help out?
(Obviously I'm a noob at this so if you need any other information I've left out please let me know).
UPDATE
The problem was with the base directory. The updated, working program is as follows:
#include <iostream>
#include <sys/stat.h>
using namespace std;
int main() {
cout << "Current directory: " << system("cd") << endl;
char path[] = "./bin/Release/myfolder";
struct stat status;
if(stat(path,&status)==0) { cout << "Directory found." << endl; }
else { cout << "Can't find directory." << endl; } //Doesn't exist
cin.get();
return 0;
}
ANOTHER UPDATE
Turns out that a trailing backslash on the path is big trouble.
Right before your stat call, insert the code:
system("pwd"); // for UNIXy systems
system("cd"); // for Windowsy systems
(or equivalent) to check your current directory. I think you'll find it's not what you think.
Alternatively, run the executable from the command line where you know what directory you're in. IDEs will frequently run your executable from a directory you may not expect.
Or, use the full path name so that it doesn't matter which directory you're in.
For what it's worth, your first code segment works perfectly (gcc under Ubuntu 10):
pax$ ls my*
ls: cannot access my*: No such file or directory
pax$ ./qq
Cannot find folder.
pax$ mkdir myfolder
pax$ ll -d my*
drwxr-xr-x 2 pax pax 4096 2010-12-14 09:33 myfolder/
pax$ ./qq
Folder found.
Are you sure that the current directory of your running program is what you expect it to be? Try changing path to an absolute pathname to see if that helps.
Check your PWD when you running your program. This problem is not caused by compiler. You DevCpp may set a working directory for your program automatically.
You can find out why stat() failed (which is a C function, not C++, by the way), by checking errno:
#include <cerrno>
...
if (stat(path,&status) != 0)
{
std::cout << "stat() failed:" << std::strerror(errno) << endl;
}