I am trying to port an existing code tree to the meson build system on a centos 7 machine. Meson configure works fine, but when I try to compile, it fails. The code is proprietary, so I have created an example that illustrates the problem (accurately enough, I hope.) I am not at liberty to restructure the directory tree.
Here's the tree:
mesonex/
alpha/
beta/
alpha/
inc/
funcs.h
numbers.h
src/
numbers.cpp
funcs.cpp
src/
example.cpp
meson.build
My meson.build:
project('example', 'cpp')
srcs=['example.cpp']
srcs+='../beta/alpha/src/funcs.cpp'
srcs+='../beta/alpha/src/funcs.cpp'
incdirs=include_directories('../beta/alpha/inc')
executable('example', srcs, include_directories: incdirs)
here is the main example.cpp file:
#include <iostream>
#include "../beta/alpha/inc/numbers.h"
#include "../beta/alpha/inc/funcs.h"
int main()
{
std::cout << "Hello" << std::endl;
std::cout << interestingNumber() << std::endl;
std::cout << interestingFunc() << std::endl;
}
These are the supporting cpp files:
// funcs.cpp
#include "../inc/numbers.h"
float interestingFunc()
{
return (interestingNumber()+1)/2;
}
// numbers.cpp
float interestingNumber()
{
return 11.3355;
}
And these are the header files:
// funcs.h
float interestingFunc();
// numbers.h
float interestingNumber();
Please note that the duplication in directory names is intentional. Maybe this confuses meson in figuring out how to handle the #includes?
This is just one example of many different build strategies I have tried.
I see right off the bat an issue that might just be an issue with your example, and not with your actual code: Meson considers the meson.build file with the project() call to be the "root" of the source directory structure. You cannot ask it to include files outside of the root. It would be about like cp /../foo . on a Unix-like OS. This may just be a mistake in your example, since this isn't the real code of course.
So, if we rewrite this as (mesonex/alpha/meson.build):
# no project(), that would be in mesonex/meson.build)
sources = files(
'example.cpp',
'../beta/alpha/src/funcs.cpp',
'../beta/alpha/src/numbers.cpp', # you have a typo in your example, funcs.cpp is listed twice.
)
executable(
'example',
sources,
include_directories : include_directories('../beta/alpha/inc'),
)
Should work.
Note, that you might want to consider using a convenience static library instead of reaching back to the code, as this is best practice, you could write something like (mesonex/alpha/beta/meson.build):
lib_beta = static_library(
'beta',
['src/funcs.cpp', 'src/numbers.cpp']
)
idep_beta = declare_dependency(
link_with : lib_beta,
include_directories : include_directories('.'),
)
and then in (src/meson.build):
executable(
'example',
'source.cpp',
dependencies : idep_beta
)
is all you need, as the idep_beta carries both the linkage and the include information.
This is a follow on - the solution worked for my example but not for the actual code. My model must have been incomplete (in a way I haven't determined yet.) The configuration stage works, but in the compile stage the #includes in the cpp source are flagged with a "File or directory does not exist." How does meson reconcile the specified include directories with #include statements in the source? The #include paths may be relative to the actual directory of the actual cpp source. Does this mean I have to edit all the #includes in all the sources - that would be a real negative. We work with some VERY large code bases.
Related
Currently, I try to build a library with Bazel (5.1.0) that originally uses CMake as a build system.
I am running into a problem when trying to include a generated a header file using a relative path (in the CMake build it uses configure_file):
(The following example can also be found here)
WORKSPACE.bazel:
workspace(name = "TemplateRule")
main.cpp:
#include "kernels/bvh/some_header.h"
#include <iostream>
int main() {
std::cout << VERSION_STR << std::endl;
}
kernels/bvh/some_header.h:
#pragma once
// include config.h using a relative path
// if changed to kernels/config.h everything works as expected
// unfortunately, this is legacy code that I cannot change
#include "../config.h"
config.h.in:
#pragma once
#define VERSION_STR "#VERSION_STR#"
BUILD.bazel
load("//bazel:expand_template.bzl", "expand_template")
expand_template(
name = "config_h",
template = "config.h.in",
out = "kernels/config.h",
substitutions = {
"#VERSION_STR#": "1.0.3",
},
)
cc_binary(
name = "HelloWorld",
srcs = [
"main.cpp",
"kernels/bvh/some_header.h",
":config_h",
],
)
bazel/BUILD.bazel: < empty >
bazel/expand_template.bzl:
# Copied from https://github.com/tensorflow/tensorflow/blob/master/third_party/common.bzl with minor modifications
# SPDX-License-Identifier: Apache-2.0
def expand_template_impl(ctx):
ctx.actions.expand_template(
template = ctx.file.template,
output = ctx.outputs.out,
substitutions = ctx.attr.substitutions,
)
_expand_template = rule(
implementation = expand_template_impl,
attrs = {
"template": attr.label(mandatory = True, allow_single_file = True),
"substitutions": attr.string_dict(mandatory = True),
"out": attr.output(mandatory = True),
},
output_to_genfiles = True,
)
def expand_template(name, template, substitutions, out):
_expand_template(
name = name,
template = template,
substitutions = substitutions,
out = out,
)
When I run bazel build //...
I get the error:
In file included from main.cpp:1:
kernel/some_header.h:3:10: fatal error: ../config.h: No such file or directory
3 | #include "../config.h"
| ^~~~~~~~~~~~~
When I include config.h in main.cpp and remove it from kernel/bvh/some_header.h everything works as expected.
Any ideas how to the relative path .../config.h working?
Creating the file config.h and compiling the code manually works as expected:
g++ main.cpp kernel/bvh/some_header.h config.h
According to the Best Practices relative paths using .. should be avoided, but you can find such things in legacy code that uses CMake to build. Is this a restriction of Bazel? or is there a workaround?
While behaviour and order of search for file while using quotes is technically platform defined, most common principle in case of use path relative to file from which inclusion happens. For kernel/bvh/some_header.h the path ../config.h is resulting in searching ONLY in kernel folder, working folder or kernel/bvh/ will not be checked. Some compilers check alternative locations. The order of search is part of compiler documentation.
I once saw use of ../../config.h inside of another header kernel.h in situation like this and it worked. It was a maintenance liability. The kernel.h was moved to different location and it picked up a wrong folder and wrong file, which resulted in ODR breach much later in project's timeline. One who had committed the move had left ../../config.h in place and made a copy. Some units were using old header while other started to use modified one at new location.
For that reason the use reverse relative paths outside of library infrastructure is not recommended. Instead partial relative paths, e.g. kernel/config.h are preferred, assuming that core folder would be in list of include paths. In practice real projects can use preprocessor macros, e.g.#include KERNEL_CONFIG_FILE. An illustration can be seen in freetype, boost, etc.
I'm new to cpp in eclipse and trying to mess with simple builds. I have made a basic project which automatically generates build info (no user-defined makefile).
Simple (Working) Case
I made a "Hello World" project called Test (not an empty project). It has one file - Test.cpp with a main() in => builds and runs fine.
Test.cpp
int main() {
// output some stuff
}
Slightly More Complex (Working) Case
I make a new file called Main.cpp. Move the main() function into Main.cpp and make a decleration of a function in main too - void test();
The test() function lives in Test.cpp, which is where I provide the function definition.
Main.cpp
#include <iostream>
void test();
int main() {
// Use test()
}
Test.cpp
#include <iostream>
void test() {
// output some stuff
}
Build it, there are now two .o files in the Debug directory - Test.o and Main.o. This runs fine.
The Problem
Now I try to introduce a third file - Limits.cpp.
Limits.cpp
#include <iostream>
void printLimits() {
// Print out limits for different integer sizes
}
Again I provide a deceleration of this function in Main.cpp.
Main.cpp
#include <iostream>
void test();
void printLimits();
int main() {
// Use printLimits()
}
This time there is no object file created for Limits in the Debug folder => the build fails.
Main.cpp:*line* undefined reference to `getLimits()'
It just looks like the autogenerated build config for the project is duff. I've tried looking around the project properties but I have had no luck. I've tried including the path/file in Include Paths/Include files, other objects, and I've checked just about every other property I can see. This has been frustrating me for two days.
The strange thing about this is case 2. It looks like because Test.cpp was the first file made it always includes this in the build? (even if it is not imported). Where as because Limits.cpp is new and not imported it doesn't generate an object file so it can't link the function.
I could me making an error by needing to include the files but my understanding is if all the object files make it to the linker then all will be well (ie I just need the function declarations when making the object files which is what I have here).
With a "Blank project" it seems to compile all the cpp files even if they are never used so my case above works. (Although, it doesn't work for files in subfolders of src). Looks like its a "feature" of the "Hello world" project type but it's going to drive me crazy knowing there must be a way to get it to do this.
If anyone knows if it is possible to include this file without writing my own makefile (I'm not a makefile guru (yet!)), or let me know if this is not possible with autogen CDT that would be great.
Using MinGW GCC toolchain.
Thanks
this will probably a dumb question for you guy's but I have no experience in C++ what so ever. I'm using an open source project osrm (which is awesome). Still to request a route, you have make an http request. To reduce the running time, I would like to build a wrapper around the code and call it using the command line. So I googled a bit and found that osrm already creates a static lib (.a file) when compiling the project. I also found a piece of code that points me in the right directions for building a wrapper. So to begin I build a simple hello world program (see below) that includes some files from that static lib. To compile I followed this tutorial.
My directory structure looks like this:
./helloWorld.cpp
./libs/libOSRM.a
And the command to compile is this:
gcc –static helloworld.cpp –L ./libs –l libOSRM.a
The code it selve:
#include "Router.h"
#include "boost/filesystem/path.hpp"
#include "ServerPaths.h"
#include "ProgramOptions.h"
#include <InternalDataFacade.h>
#include <viaroute.hpp>
#include <iostream.h>
main()
{
cout << "Hello World!";
return 0;
}
the exact error I got:
fatal error: ServerPaths.h: No such file or directory #include "ServerPaths.h"
Add the -IPathToTheHeaderFiles to the compiler options. So it will find the files to be included. Replace PathToTheHeaderFiles with the path where your file ServPaths.h resides.
Edit: Add as many -I as you need for further header files.
Additionally it would be worth to read a book about C++ or/and the GCC manual1
1 Section 3.11 will help.
Some time ago I started a big header library in C++1x using XCode. The current layout of the library is () something like (partial output from ls -R sponf)
sponf/sponf:
ancestors sponf.h sponf_utilities.h
categories sponf_children.h utilities
children sponf_macros.h
sponf/sponf/ancestors:
function.h meter.h set.h simulation.h
sponf/sponf/categories:
free_space.h prng.h random_distribution.h series.h
sponf/sponf/children:
distributions histogram.h random simulations
meters numeric series spaces
sponf/sponf/children/distributions:
arcsine_der.h exponential.h
box_muller.h uniform.h
sponf/sponf/children/meters:
accumulator.h timer.h
#... other subdirs of 'children' ...
sponf/sponf/utilities:
common_math.h limits.h string_const.h
#... other directories ...
I wanted to port this project to CLion, which seems a really good IDE (based on the similar AndroidStudio IDE) but I'm getting some troubles.
Small test program
I tried this small program as a test:
#include <iostream>
#include <sponf/sponf.h>
using namespace std;
int main() {
using space = sponf::spaces::euclidean_free_space<double, 3>;
sponf::simulations::random_walk<space> rw;
rw.step(1);
std::cout << rw.position.value << std::endl;
return 0;
}
The program compiles and runs fine. However, CLion does not recognize the spaces namespace (declared in one of the children files), nor the simulations namespace; they are both marked red and I cannot inspect their content, nor navigate to their definitions by ⌘-clicking, etc. etc...
Relevant parts of the library
Looking in "sponf.h" we find
#ifndef sponf_h
#define sponf_h
/* The classes below are exported */
#pragma GCC visibility push(default)
// include some of the standard library files
// ...
#include <Eigen/Eigen>
#include "sponf_macros.h"
#include "sponf_utilities.h"
#include "sponf_children.h"
#pragma GCC visibility pop
#endif
while in "sponf_children.h" (which is located at the top level, next to "sponf.h") we find
#ifndef sponf_locp_sponf_children_h
#define sponf_locp_sponf_children_h
namespace sponf {
// include some of the children
// ...
#include "children/spaces/euclidean_free_space.h"
#include "children/simulations/random_walk.h"
// include remaining children
// ...
}
#endif
Each "child" header will then include its corresponding "ancestor" or "category" header (which defines the superclass of the "child" itself).
The reaction of CLion
Despite the autocompletition prediction, which easily finds all the subdirectories and the headers, all the include directives in this last file get marked red and ⌘-clicking on any of them leads to a popup message
Cannot find declaration to go to
while the right ribbon of the editor signal many errors like
',' or ) expected
) expected
Declarator expected
Expecting type
Missing ;
Unexpected symbol
which are not the same for each include statement (each generates from 2 to all of these errors).
On the other hand, CLion is perfectly able to find all Eigen headers, which have pretty much the same structure!
I have put both libs in /opt/local/include and changed CMakeLists.txt accordingly
cmake_minimum_required(VERSION 2.8.4)
project(sponf)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
include_directories(/opt/local/include/sponf /opt/local/include/eigen3)
set(SOURCE_FILES main.cpp)
add_executable(sponf ${SOURCE_FILES})
Why can't CLion properly parse the project structure? XCode, after having included /opt/local/include/sponf and /opt/local/include/eigen3 in the HEADER_SEARCH_PATHS env. variable of the project, is able to find any header while compiling the same exact program.
Is there anything else I need to know? Am I doing it wrong or is it that CLion isn't that mature yet and this is just a sorry bug? This is my first approach to the CLion and the CMake toolchain, so any kind of information about it will be greatly appreciated!
Sorry for the very long question, I didn't manage to shrink it further... Thanks in advance guys, see you soon!
Here what I did in windows using cigwin64. I wanted to use Eigen library include in my project.
Eigen library is places in /usr/include/eigen then edited CMakeLists.txt and add
include_directories("/usr/include/eigen")
into it. Now CLion can find all source files in eigen lib. May be this what you wanted too.
Downgrade to Clion 2016.1.4 fixes the problem
I'm trying to link jsoncpp (lib_json) with a c++ project using cmake. It works perfectly fine on one computer, but on another one (with pretty much the same config) i get an error when i execute my app :
dyld: Library not loaded: buildscons/linux-gcc-4.2.1/src/lib_json/libjson_linux-gcc-4.2.1_libmt.dylib
Referenced from: path to executable
Reason: image not found
Any idea what might be causing this ? I don't even understand why it tries to look # buildscons/linux-gcc-4.2.1/src/lib_json/libjson_linux-gcc-4.2.1_libmt.dylib since i put jsoncpp in usr/lib/ and changed the name to libjsoncpp and cmake find the correct path/library.
I also built jsoncpp the exact same way on both computers.
I had the same problem. If you run tool -L libjson_linux-gcc-4.2.1_libmt.dylib you can see some weird relative address to your libjson.... I guess if you replicated this directory structure it would work but that's a bad solution.
What I did instead is that I used .a (libjson_linux-gcc-4.2.1_libmt.a) and linked it staticaly with my binary. In XCode simply under Build Settings -> Linking -> Other Linker Flags I added absolute path to my .a. For me it was /Users/martin/Downloads/jsoncpp-src-0.5.0/libs/linux-gcc-4.2.1/libjson_linux-gcc-4.2.1_libmt.a and that's all.
Of course, I don't know your use case, maybe you really need to link it dynamically.
EDIT: I see now, you mean libjson, and not libjsoncpp (they're different!)
In your titel you talk about jsoncpp, and that's what this answer is for.
But maybe it's useful for people who got confused by the titel too.
You can 'amalgamate' jsoncpp.
From jsoncpp source dir run python amalgamate.py which creates:
dist/jsoncpp.cpp
dist/json/json.h
dist/json/json-forwards.h
Now you have to compile jsoncpp.cpp once and just link against the resulting jsoncpp.o:
g++ -o jsoncpp.o -c jsoncpp.cpp (only once)
g++ -o executable jsoncpp.o main.cpp (every time)
If you get errors, you might have to #define JSON_IS_AMALGAMATION before including json/json.h, but ...
... I tried it and it worked for me. (without #define JSON_IS_AMALGAMATION, that is)
Used code:
#include "json/json.h"
#include "json/json-forwards.h"
int main(int argc, char *argv[])
{
Json::Reader reader;
Json::Value value;
if (!reader.parse("{\"hello\":\"world\"}", value, false))
{
std::cerr << "ERROR: Couldn't parse Json: " << reader.getFormattedErrorMessages() << std::endl;
return -1;
}
std::cout << value.toStyledString() << std::endl;
return 0;
}