So recently I've been trying out autotools to build a C++ Library. Originally I was just working on pure custom classes, which is quite easy to just #include and then compile with g++. But when I want to write some custom functions for the library, I've learnt that it's a bad practice to write functions within header file, but rather I should declare it in header then wrote it in a separate .cpp file. Which later I've tried and successfully compiled with g++ ./lib/**/*.cpp src/main.cpp.
So basically my project structure is that codes are put under src/, headers are under include/ and functions are put under lib/. And following is my src/Makefile.am
AUTOMAKE_OPTIONS = subdir-objects foreign
bin_PROGRAMS = main
include_HEADERS = -I../include/**/*.hpp
main_SOURCES = -I../lib/**/*.cpp main.cpp
And for the endpoints' directory (under lib/) I have something like following
main_SOURCES = stdout.cpp
But it gave me error that no program named main, so I figured maybe all those function files has to be compiled first, so I changed them into
noinst_PROGRAMS = stdout
stdout_SOURCES = stdout.cpp
But then they gave me the following error
/usr/sbin/ld: /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../lib/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status
I know that the error meant that there's no main() written in the file, but since it's a library function file, it doesn't meant to have a main(), it's meant to be called by other file (like main.cpp). And to here I'm stuck.
I've tried to find documentation online, but it seems that most of them are targeted at C programs instead of C++, which I'm not sure if those steps are compatible. And I remember C++ libraries are compiled into .so or .o file while most tutorials seems to be using .la files.
MWE
src/main.cpp
#include"../include/conn/bash/stdout.hpp"
#include<string>
#include<iostream>
int main() {
std::string o=d::conn::bash::exec("ls");
std::cout << o << std::endl;
return 0;
}
include/conn/bash/stdout.hpp
#ifndef __CONN_BASH_O__
#define __CONN_BASH_O__
#include<string>
namespace d { namespace conn { namespace bash {
std::string exec(const char*);
}}}
#endif
lib/conn/bash/stdout.cpp
#include"../../../include/conn/bash/stdout.hpp"
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>
std::string d::conn::bash::exec(const char* cmd) {
std::array<char, 128> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
}
// https://stackoverflow.com/a/478960/8460574
Compiled and tested with g++ ./lib/**/*.cpp src/main.cpp