Try to make hello world project with external ASM function in CPP.
CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(TestProject VERSION 0.1 LANGUAGES CXX ASM)
set_property(SOURCE foo.s APPEND PROPERTY COMPILE_OPTIONS "-x" "assembler-with-cpp")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_executable(TestProject main.cpp foo.s)
target_include_directories(TestProject PUBLIC
"${PROJECT_BINARY_DIR}"
)
foo.s
.text
.globl _foo
_foo:
add %esi, %edi // add x and y
mov %edi, %eax // move result to correct register for return value
ret
main.cpp
#include <iostream>
using namespace std;
int foo(int x, int y);
int main() {
int result = foo(100, 200);
cout << result << endl;
}
I can generate project for my IDE successfully
cmake .. -G Xcode
And if I build it in IDE I get this error:
Error
Undefined symbol: foo(int, int)
And if I try to build from terminal
cmake --build ..
I get error with CMakeCache.txt:
Error: could not load cache
CPP (only) projects builds fine on the machine.
Suppose something wrong with generated CMakeCache.txt but can get it.
CMakeCache.txt:
https://pastebin.com/BSbZfA67
You have declared foo to have C++ linkage but defined it to have C linkage. To fix this problem, declare foo to have C linkage instead:
extern "C" int foo(int x, int y);
Related
Ok, I have this strange bug, or behavior I don't understand. If I use -static-libstdc++ link flag in my project, LLDB fails to show underlying type of a pointer. So here is small example. I have the very basic test executable, with only one main.cpp file:
// main.cpp
#include <memory>
class TestBase
{
public:
TestBase() = default;
virtual ~TestBase() = default;
int m_baseInt = 10;
};
class TestDerived : public TestBase
{
public:
TestDerived() = default;
virtual ~TestDerived() override = default;
int m_derivedInt = 20;
};
int main(int,char*[])
{
std::unique_ptr<TestBase> regularBase = std::make_unique<TestBase>();
std::unique_ptr<TestBase> hiddentBase = std::make_unique<TestDerived>();
TestBase*volatile base = hiddentBase.get();
volatile int breakpoint = 10;
++breakpoint;
}
and one CMake file to build it
# CMakeLists.txt
cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)
project(quick-test VERSION 0.1.0 LANGUAGES CXX C)
add_executable(test-exe "main.cpp")
For ide I use vscode with CodeLLDB module, and so if you look at 'base' variable it will show TestDerived class (as it should):
But with only one chage, by adding -static-libstdc++ link option to my test executable
# CMakeLists.txt
cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)
project(quick-test VERSION 0.1.0 LANGUAGES CXX C)
add_executable(test-exe "main.cpp")
target_link_options(test-exe PRIVATE -static-libstdc++)
now lldb is incapable to deduce underlying type of a 'base' pointer:
For compilation I used clang 14.0.0 and gcc 11.2.0, but it didn't make any difference.
Why does linking statically c++ std lib causes this, and is there any solution for this accept removing this flag?
I have seens some answers, but most of them does not work for me. So I would like to make everything clear by adding a new question, my CMakeLists.txt is like this:
cmake_minimum_required(VERSION 3.17)
project(example)
include_directories(./)
link_directories(./)
if (CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Os -g ${CMAKE_CXX_FLAGS}")
message("CMAKE_COMPILER_IS_GNUCXX is True")
message("option is: ${CMAKE_CXX_FLAGS}")
endif (CMAKE_COMPILER_IS_GNUCXX)
add_executable(main try.cpp)
target_link_libraries(main fun)
set_property(TARGET main PROPERTY POSITION_INDEPENDENT_CODE 1 LINK_FLAGS -pie)
add_library(fun SHARED func.cpp)
# target_compile_options(fun PUBLIC "-pie")
target_link_libraries(fun PUBLIC "-pie")
set_property(TARGET fun PROPERTY POSITION_INDEPENDENT_CODE 1)
And the source code for try.cpp is:
#include<iostream>
#include "func.hpp"
int main() {
using namespace std;
cout << "hello from exe main" << endl;
func();
return 0;
}
The code for fun.cpp and fun.hpp is like this:
// func.hpp
void func();
// func.cpp
#include <iostream>
using std::cout;
using std::endl;
void func() {
cout << "hell from so func\n";
}
int main() {
cout << "hello from so main\n";
return 0;
}
My problem is that: I got the following link error when I compile it with cmake:
Scanning dependencies of target fun
[ 25%] Building CXX object CMakeFiles/fun.dir/func.cpp.o
[ 50%] Linking CXX shared library libfun.so
[ 50%] Built target fun
Scanning dependencies of target main
[ 75%] Building CXX object CMakeFiles/main.dir/try.cpp.o
[100%] Linking CXX executable main
/usr/bin/ld: CMakeFiles/main.dir/try.cpp.o: in function `main':
/home/coin/learn-coding/projects/C/cmake/try.cpp:8: undefined reference to `func()'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/main.dir/build.make:105: main] Error 1
make[1]: *** [CMakeFiles/Makefile2:125: CMakeFiles/main.dir/all] Error 2
make: *** [Makefile:104: all] Error 2
What is the problem with the configuration and how could I make it work ?
By the way, I tried to compile with command line:
g++ -fPIC -pie func.cpp -o libfun.so -shared
g++ try.cpp -o main -L. -lfun
Which does work when I run the generated main, but the generated so file cannot be runnable:
$ ./main
hello from exe main
hell from so func
$ ./libfun.so
Segmentation fault (core dumped)
What did I miss here ?
The following files based on this answer:
cat >CMakeLists.txt <<EOF
cmake_minimum_required(VERSION 3.17)
project(example)
if(CMAKE_COMPILER_IS_GNUCXX)
add_compile_options(
$<$<COMPILE_LANGUAGE:CXX>:-std=c++11>
-Wall
-Os
-g
)
endif()
add_executable(main try.cpp)
target_link_libraries(main PRIVATE fun)
add_library(fun SHARED func.cpp)
target_link_options(fun PRIVATE -Wl,-e,entry_point)
EOF
cat >func.cpp <<EOF
// func.hpp
void func();
// func.cpp
#include <iostream>
using std::cout;
using std::endl;
void func() {
cout << "hell from so func\n";
}
static inline
int lib_main() {
printf("hello from so main\n");
return 0;
}
extern "C" const char interp_section[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";
extern "C" void entry_point()
{
lib_main();
exit(0);
}
EOF
cat >try.cpp <<EOF
#include<iostream>
void func();
int main() {
using namespace std;
cout << "hello from exe main" << endl;
func();
return 0;
}
EOF
when compiled with the following on my 64-bit system with glibc, it generates two files that are executable:
$ cmake -S . -B _build && cmake --build _build -- VERBOSE=1
balbla compilation output
$ _build/main
hello from exe main
hell from so func
$ _build/libfun.so
hello from so main
I replaced std::cout with printf because I received a segmentation fault - I suspect global constructors are not beeing run and something in iostream destructors makes it go segfault.
I think adding LINK_FLAGS -pie) and target_link_libraries(fun PUBLIC "-pie") makes no point, it's handled with POSITION_INDEPENDENT_CODE property and I guess for shared library it's TRUE anyway (but I am not sure about that).
Good day,
here is my code
#include <iostream>
#include <Magick++.h>
using namespace std;
using namespace Magick;
int main(int argc, char **argv) {
InitializeMagick(*argv);
Image image;
try {
image.read(argv[1]);
}
catch( Exception &error_ ) {
cout << "Caught exception: " << error_.what() << endl;
return 1;
}
int x = image.columns();
cout<<"your picture's width is "<< x << "px"<<endl;
return 0;
}
I use KDevelop(which uses CMake as builder),
when I try to compile the app, it throws me an error
main.cpp:25: undefined reference to `Magick::Image::columns() const'
Here's what my CMakeLists.txt contains.
cmake_minimum_required(VERSION 3.5)
project(hello)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES main.cpp)
add_executable(hello ${SOURCE_FILES})
add_definitions( -DMAGICKCORE_QUANTUM_DEPTH=16 )
add_definitions( -DMAGICKCORE_HDRI_ENABLE=0 )
find_package(ImageMagick COMPONENTS Magick++)
include_directories(${ImageMagick_INCLUDE_DIRS})
target_link_libraries(hello ${ImageMagick_LIBRARIES})
I figured out that there're often issues with undefined references when CMakeLists isn't written correctly, but I made it according to this About Magick++, how to write the CMakeLists?
where am I wrong? I can add any information needed.
UPD 1.
version of magick++,
8:6.8.9.9-7ubuntu5.7
system info:
Description: Linux Mint 18.1 Serena
UPD 2.
I just removed parenthesis and when tryed to compile with
size_t x = image.columns;
size_t y = image.rows;
KDevelop threw me
main.cpp:25:22: error: cannot convert ‘Magick::Image::columns’ from type ‘size_t (Magick::Image::)() const {aka long unsigned int (Magick::Image::)() const}’ to type ‘size_t {aka long unsigned int}’
even when
auto x = image.columns;
auto y = image.rows;
it throws
main.cpp:25:20: error: cannot convert ‘Magick::Image::columns’ from
type ‘size_t (Magick::Image::)() const {aka long unsigned int
(Magick::Image::)() const}’ to type ‘long unsigned int
(Magick::Image::*)() const’
what's happening?
P.S. hooray, this is my first question on stackoverflow! :-)
If you are able to compile your program without CMake using g++ main.cpp `Magick++-config --cxxflags --cppflags --ldflags --libs` (but for some reason cannot use ${ImageMagick_LIBRARIES} in CMake), then you can make use of Magick++-config in your CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(hello LANGUAGES CXX)
add_executable(hello main.cpp)
target_compile_features(hello PRIVATE cxx_std_11)
find_package(ImageMagick REQUIRED COMPONENTS Magick++)
target_compile_definitions(hello PRIVATE
MAGICKCORE_QUANTUM_DEPTH=16
MAGICKCORE_HDRI_ENABLE=0
)
target_include_directories(hello PRIVATE ${ImageMagick_INCLUDE_DIRS})
execute_process(COMMAND Magick++-config --ldflags
OUTPUT_VARIABLE ImageMagick_LINK_FLAGS
OUTPUT_STRIP_TRAILING_WHITESPACE
)
target_link_libraries(hello PRIVATE ${ImageMagick_LINK_FLAGS})
Here, execute_process allows us to get the result of Magick++-config --ldflags into a variable, which we can pass as flags to the linker through target_link_libraries.
Also, note how I've used target_compile_features rather than setting the global CMAKE_CXX_FLAGS variable, target_compile_definitions rather than add_definitions and target_include_directories rather than include_directories. It's better to use local (target-based) commands rather than modifying global state, both in programming and in CMake, since they can have unforeseen repercussions down the line -- in the context of CMake, those global commands would have affected nested sub-projects.
ForgottenUbrella 's version which I adapted didn't quite work for me, copying a line in from another project fixed it. Note, I'm using c++20 not 11.
I had the following error:
..... undefined reference to symbol 'pthread_create##GLIBC_2.2.5'
and the line that fixed it:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a -pthread")
I am having issues with compiling my CUDA code with CMake. I am using CUDA 7 and the version information from nvcc is as follows:
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2014 NVIDIA Corporation
Built on Tue_Dec__9_18:10:46_CST_2014
Cuda compilation tools, release 7.0, V7.0.17
My CMake file uses the find_cuda macro as follows:
find_package(CUDA)
if(CUDA_FOUND)
list(APPEND CUDA_NVCC_FLAGS "-arch=sm_20;--compiler-options;-std=c++11;-O2;-DVERBOSE")
endif(CUDA_FOUND)
I added the std=c++11 compiler flag after many posts suggested this was needed. However, I get exactly the same errors with or without this flag.
I also added the following to remove the C++11 support from nvcc compilation flags but this does not change anything either.
if(CMAKE_COMPILER_IS_GNUCC)
string(REPLACE "-std=c++11" "" CUDA_HOST_FLAGS "${CUDA_HOST_FLAGS}")
string(REPLACE "-std=c++0x" "" CUDA_HOST_FLAGS "${CUDA_HOST_FLAGS}")
endif(CMAKE_COMPILER_IS_GNUCC)
The errors I get are as follows:
/usr/lib/gcc/x86_64-linux-gnu/4.8/include/stddef.h(432): error: identifier "nullptr" is undefined
/usr/lib/gcc/x86_64-linux-gnu/4.8/include/stddef.h(432): error: expected
a ";"
/usr/include/x86_64-linux-gnu/c++/4.8/bits/c++config.h(190): error:
expected a ";"
/usr/include/c++/4.8/exception(63): error: expected a ";"
/usr/include/c++/4.8/exception(68): error: expected a ";"
/usr/include/c++/4.8/exception(76): error: expected a ";"
/usr/include/c++/4.8/exception(83): error: expected a ";"
/usr/include/c++/4.8/exception(93): error: expected a "{"
/usr/include/c++/4.8/bits/exception_ptr.h(64): error: function
"std::current_exception" returns incomplete type
"std::__exception_ptr::exception_ptr"
I am using gcc 4.8 but get the same errors with 4.7 as well. I am on cmake 2.8.12.2.
Compiling with CMAKE verbose gives the following flags for nvcc compilation:
/usr/local/cuda-7.0/bin/nvcc /home/xargon/Dropbox/code/gpu-mosaicing
/src/gpu/kernels/bgra_2_gray.cu -c -o /home/xargon/code/mosaicing_bin
/gpu/kernels/CMakeFiles/kernels.dir//./kernels_generated_bgra_2_gray.cu.o
-ccbin /usr/bin/cc -m64 -DUSE_CUDA -DUSE_OPENCV -DUSE_QT -Xcompiler
,\"-std=c++11\",\"-O3\",\"-DNDEBUG\" -arch=sm_20 --compiler-options
-std=c++11 -O2 -DVERBOSE -DNVCC -I/usr/local/cuda-7.0/include -I/usr/local
/include/opencv -I/usr/local/include -I/home/xargon/Dropbox/code/gpu-
mosaicing/src/cpu/gui/qt -I/usr/include -I/home/xargon/Dropbox/code/gpu-
mosaicing/src/cpu/core -I/home/xargon/Dropbox/code/gpu-mosaicing/src/cpu
/datasources -I/home/xargon/Dropbox/code/gpu-mosaicing/src/gpu
/intraoperability -I/home/xargon/Dropbox/code/gpu-mosaicing/src/utils
-I/usr/local/cuda-7.0/include
This worked for me using CUDA 7, gcc 4.8.2 and CMake 3.0.2.
I updated the code and added a simple thrust-based example to make it clear that you can use C++11 in CUDA code
CMakeLists.txt
project(cpp11)
find_package(CUDA)
list(APPEND CUDA_NVCC_FLAGS "-arch=sm_20;-std=c++11;-O2;-DVERBOSE")
SET(CUDA_PROPAGATE_HOST_FLAGS OFF)
CUDA_ADD_EXECUTABLE(cpp11 main.cpp test.h test.cu)
test.h
#ifndef TEST_H
#define TEST_H
int run();
#endif
test.cu
#include "test.h"
#include <thrust/device_vector.h>
#include <thrust/reduce.h>
#include <thrust/sequence.h>
template<typename T>
struct Fun
{
__device__ T operator()(T t1, T t2)
{
auto result = t1+t2;
return result;
}
};
int run()
{
const int N = 100;
thrust::device_vector<int> vec(N);
thrust::sequence(vec.begin(),vec.end());
auto op = Fun<int>();
return thrust::reduce(vec.begin(),vec.end(),0,op);
}
main.cpp
#include <iostream>
#include "test.h"
int main()
{
std::cout << run() << std::endl;
return 0;
}
list(APPEND CUDA_NVCC_FLAGS "-std=c++11") is enough,SET(CUDA_PROPAGATE_HOST_FLAGS OFF) may be not necessary, and it cause me could not set breakpoint in .cu file
If stumbling across this question while searching for a way to compile Genoils CPP-Ethereum build for Ethereum CUDA mining, my problem was solved by editing the CMakeLists.txt file in the cpp-ethereum/libethash-cuda folder.
Where it states:
set(CUDA_NVCC_FLAGS
${CUDA_NVCC_FLAGS};
-gencode etc etc)
add "-std=c++11" after the semi-colon, as follows:
set(CUDA_NVCC_FLAGS
${CUDA_NVCC_FLAGS};
-std=c++11
-gencode etc etc)
I have the following c++ code for testing:
#include <lua.hpp>
#include <iostream>
static int dummy(lua_State * L)
{
std::cout << "Test";
return 0;
}
int luaopen_testlib(lua_State * L)
{
lua_register(L,"dummy",dummy);
return 0;
}
I compile it with commands and it gives me no errors:
g++ -Wextra -O2 -c -o testlib.o main.cpp
g++ -shared -o testlib.so testlib.o
But when i try to load it in lua i get undefined symbol error as this:
Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio
> require"testlib"
error loading module 'testlib' from file './testlib.so':
./testlib.so: undefined symbol: _Z16lua_pushcclosureP9lua_StatePFiS0_Ei
It seems for me that there is something missing in the g++ commands, but i have been searching solution for whole morning and can't get this simple example to compile.
EDIT:
after few recompilations it returned to:
error loading module 'testlib' from file './testlib.so':
./testlib.so: undefined symbol: luaopen_testlib
which was solved by adding :
extern "C"
{
int luaopen_testlib(lua_State *L)
{
lua_register(L,"dummy",dummy);
return 0;
}
}
The Lua binary is compiled as C code, the library tries to use it as C++. That will not work as C++ does name mangling to support overloading. As C does not support overloading it does not need the name mangling and will not understand mangled names.
The solution to this is to tell the C++ compiler that the Lua functions it is going to interact with are straight C and they need no name mangling.
Also the luaopen_testlib function must be extern "C" as it will be called from C code with no mangling.
extern "C" {
#include <lua.h>
}
#include <iostream>
static int dummy(lua_State * L)
{
(void)L;
std::cout << "Test"<<std::endl;
return 0;
}
extern "C"
int luaopen_testlib(lua_State * L)
{
lua_register(L,"dummy",dummy);
return 0;
}
I ran my test with Lua 5.4.2 and used the following commands to build the library:
g++ -Wall -Wextra -O2 -Isrc -c -fPIC -o testlib.o testlib.cpp
g++ -shared -o testlib.so testlib.o
Note the -Isrc is needed to find lua.h in my test setup and -fPIC was required to use cout in the library (but that may depend on the compiler version used).
and the result is:
Lua 5.4.2 Copyright (C) 1994-2020 Lua.org, PUC-Rio
> require 'testlib'
true ./testlib.so
> dummy
function: 0x7ff07d2a0aa0
> dummy()
Test
>
The Lua version used will, in this case, not make any difference.
Try to use Luabind. Here is the Hello World example
#include <iostream>
#include <luabind/luabind.hpp>
void greet()
{
std::cout << "hello world!\n";
}
extern "C" int init(lua_State* L)
{
using namespace luabind;
open(L);
module(L)
[
def("greet", &greet)
];
return 0;
}
This is how i would compile lua, is not exacly gcc but cmake can use gcc.
.
├── CMakeList.txt (A)
├── main.cpp
├── lua_535
│ ├── CMakeLists.txt (B)
│ └── * lua_content *
main.cpp | Just checks if it works
#include <iostream>
#include <string>
#include "lua.hpp"
int main(){
lua_State * lua = luaL_newstate();
std::string str_acction = "a = 5";
int res = luaL_dostring(lua, str_acction.c_str());
std::cout << "DS State > " << res << std::endl;
lua_close(lua);
return 0;
}
CMakeList.txt (A) | Creates the executable and links the library
cmake_minimum_required(VERSION 3.12)
project(lua_test)
add_executable(main main.cpp)
add_subdirectory("lua_535")
target_link_libraries(main PUBLIC lua_lib)
CMakeList.txt (B) | Joins Lua files into a library
Get the latest lua source files
Extract the content into a sub folder
Add this file into the folder
cmake_minimum_required(VERSION 3.12)
project( lua_lib )
set ( LUA_EMBEDDED ON )
set ( LUA_RUNTIME_MAIN "src/luac.c" )
set (LUA_RUNTIME_SOURCES
"src/lapi.c"
"src/lapi.h"
"src/lauxlib.c"
"src/lauxlib.h"
"src/lbaselib.c"
"src/lbitlib.c"
"src/lcode.c"
"src/lcode.h"
"src/lcorolib.c"
"src/lctype.c"
"src/lctype.h"
"src/ldblib.c"
"src/ldebug.c"
"src/ldebug.h"
"src/ldo.c"
"src/ldo.h"
"src/ldump.c"
"src/lfunc.c"
"src/lfunc.h"
"src/lgc.c"
"src/lgc.h"
"src/linit.c"
"src/liolib.c"
"src/llex.c"
"src/llex.h"
"src/llimits.h"
"src/lmathlib.c"
"src/lmem.c"
"src/lmem.h"
"src/loadlib.c"
"src/lobject.c"
"src/lobject.h"
"src/lopcodes.c"
"src/lopcodes.h"
"src/loslib.c"
"src/lparser.c"
"src/lparser.h"
"src/lprefix.h"
"src/lstate.c"
"src/lstate.h"
"src/lstring.c"
"src/lstring.h"
"src/lstrlib.c"
"src/ltable.c"
"src/ltable.h"
"src/ltablib.c"
"src/ltm.c"
"src/ltm.h"
"src/lua.c"
"src/lua.h"
"src/lua.hpp"
"src/luaconf.h"
"src/lualib.h"
"src/lundump.c"
"src/lundump.h"
"src/lutf8lib.c"
"src/lvm.c"
"src/lvm.h"
"src/lzio.c"
"src/lzio.h"
)
add_library( lua_lib "${LUA_RUNTIME_SOURCES}" )
if( NOT LUA_EMBEDDED)
add_library( lua_lib "${LUA_RUNTIME_MAIN}")
endif()
target_include_directories ( lua_lib PUBLIC "${PROJECT_SOURCE_DIR}/src")
If lua is enbedded src/luac.c should be excluded because conteins a int main(){}