I have the hello world program from the gtkmm documentation. I can compile the program without any issues using:
g++ -o example main.cc example.cc `pkg-config "gtkmm-4.0" --cflags --libs`
But the moment I go into neovim, coc-clangd has an error:
In included file: no template named 'is_base_of_v' in namespace 'std'; did you mean 'is_base_of'?
this happens at #include "gtkmm/application.h"
:CocInfo
vim version: NVIM v0.5.0
node version: v14.15.5
coc.nvim version: 0.0.80-37132cfc36
coc.nvim directory: /home/blah/.config/nvim/plugged/coc.nvim
term: tmux
platform: linux
clangd is 12.0.0
PS: I do have a compile_commands.json file, generated using intercept-build utility
I don't know if you have solved it now, I encountered the same problem as you. I thought it was a problem with clangd, but I checked the is_base_of_v and found that it only existed after C++17. If you use cmake to generate your project, just add:
set_property(TARGET ${target_name} PROPERTY CXX_STANDARD 17)
to your CMakeLists.txt to set the C++ standard to C++17.
Related
Clang and MSVC already supports Modules TS from unfinished C++20 standard.
Can I build my modules based project with CMake or other build system and how?
I tried build2, it supports modules and it works very well, but i have a question about it's dependency management (UPD: question is closed).
CMake currently does not support C++20 modules.
See also the relevant issue in the CMake issue tracker. Note that supporting modules requires far more support from the build system than inserting a new compiler option. It fundamentally changes how dependencies between source files have to be handled during the build: In a pre-modules world all cpp source files can be built independently in any order. With modules that is no longer true, which has implications not only for CMake itself, but also for the downstream build system.
Take a look at the CMake Fortran modules paper for the gory details. From a build system's point of view, Fortran's modules behave very similar to the C++20 modules.
Update: CMake 3.20 introduces experimental support for Modules with the Ninja Generator (and only for Ninja). Details can be found in the respective pull request. At this stage, this feature is still highly experimental and not intended for production use. If you intend to play around with this anyway, you really should be reading both the Fortran modules paper and the dependency format paper to understand what you're getting into.
This works on Linux Manjaro (same as Arch), but should work on any Unix OS. Of course, you need to build with new clang (tested with clang-10).
helloworld.cpp:
export module helloworld;
import <cstdio>;
export void hello() { puts("Hello world!"); }
main.cpp:
import helloworld; // import declaration
int main() {
hello();
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(main)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(PREBUILT_MODULE_PATH ${CMAKE_BINARY_DIR}/modules)
function(add_module name)
file(MAKE_DIRECTORY ${PREBUILT_MODULE_PATH})
add_custom_target(${name}.pcm
COMMAND
${CMAKE_CXX_COMPILER}
-std=c++20
-stdlib=libc++
-fmodules
-c
${CMAKE_CURRENT_SOURCE_DIR}/${ARGN}
-Xclang -emit-module-interface
-o ${PREBUILT_MODULE_PATH}/${name}.pcm
)
endfunction()
add_compile_options(-fmodules)
add_compile_options(-stdlib=libc++)
add_compile_options(-fbuiltin-module-map)
add_compile_options(-fimplicit-module-maps)
add_compile_options(-fprebuilt-module-path=${PREBUILT_MODULE_PATH})
add_module(helloworld helloworld.cpp)
add_executable(main
main.cpp
helloworld.cpp
)
add_dependencies(main helloworld.pcm)
Assuming that you're using gcc 11 with a Makefile generator, the following code should work even without CMake support for C++20:
cmake_minimum_required(VERSION 3.19) # Lower versions should also be supported
project(cpp20-modules)
# Add target to build iostream module
add_custom_target(std_modules ALL
COMMAND ${CMAKE_COMMAND} -E echo "Building standard library modules"
COMMAND g++ -fmodules-ts -std=c++20 -c -x c++-system-header iostream
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
# Function to set up modules in GCC
function (prepare_for_module TGT)
target_compile_options(${TGT} PUBLIC -fmodules-ts)
set_property(TARGET ${TGT} PROPERTY CXX_STANDARD 20)
set_property(TARGET ${TGT} PROPERTY CXX_EXTENSIONS OFF)
add_dependencies(${TGT} std_modules)
endfunction()
# Program name and sources
set (TARGET prog)
set (SOURCES main.cpp)
set (MODULES mymod.cpp)
# Setup program modules object library
set (MODULE_TARGET prog-modules)
add_library(${MODULE_TARGET} OBJECT ${MODULES})
prepare_for_module(${MODULE_TARGET})
# Setup executable
add_executable(${TARGET} ${SOURCES})
prepare_for_module(${TARGET})
# Add modules to application using object library
target_link_libraries(${TARGET} PRIVATE ${MODULE_TARGET})
Some explanation:
A custom target is added to build the standard library modules, in case you want to include standard library header units (search for "Standard Library Header Units" here). For simplicity, I just added iostream here.
Next, a function is added to conveniently enable C++20 and Modules TS for targets
We first create an object library to build the user modules
Finally, we create our executable and link it to the object library created in the previous step.
Not consider the following main.cpp:
import mymod;
int main() {
helloModule();
}
and mymod.cpp:
module;
export module mymod;
import <iostream>;
export void helloModule() {
std::cout << "Hello module!\n";
}
Using the above CMakeLists.txt, your example should compile fine (successfully tested in Ubuntu WSL with gcc 1.11.0).
Update:
Sometimes when changing the CMakeLists.txt and recompiling, you may encounter an error
error: import "/usr/include/c++/11/iostream" has CRC mismatch
Probably the reason is that every new module will attempt to build the standard library modules, but I'm not sure. Unfortunately I didn't find a proper solution to this (avoiding rebuild if the gcm.cache directory already exists is bad if you want to add new standard modules, and doing it per-module is a maintenance nightmare). My Q&D solution is to delete ${CMAKE_BINARY_DIR}/gcm.cache and rebuild the modules. I'm happy for better suggestions though.
CMake ships with experimental support for C++20 modules:
https://gitlab.kitware.com/cmake/cmake/-/blob/master/Help/dev/experimental.rst
This is tracked in this issue:
https://gitlab.kitware.com/cmake/cmake/-/issues/18355
There is also a CMakeCXXModules repository that adds support for modules to CMake.
https://github.com/NTSFka/CMakeCxxModules
While waiting for proper C++20 modules support in CMake, I've found that if using MSVC Windows, for right now you can make-believe it's there by hacking around the build instead of around CMakeLists.txt: continously generate with latest VS generator, and open/build the .sln with VS2020. The IFC dependency chain gets taken care of automatically (import <iostream>; just works). Haven't tried Windows clang or cross-compiling. It's not ideal but for now at least another decently workable alternative today, so far.
Important afterthought: use .cppm and .ixx extensions.
CMake does not currently support C++20 modules like the others have stated. However, module support for Fortran is very similar, and perhaps this could be easily changed to support modules in C++20.
http://fortranwiki.org/fortran/show/Build+tools
Now, perhaps there i an easy way to modify this to support C++20 directly. Not sure. It is worth exploring and doing a pull request should you resolve it.
Add MSVC version (revised from #warchantua 's answer):
cmake_minimum_required(VERSION 3.16)
project(Cpp20)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(PREBUILT_MODULE_DIR ${CMAKE_BINARY_DIR}/modules)
set(STD_MODULES_DIR "D:/MSVC/VC/Tools/MSVC/14.29.30133/ifc/x64") # macro "$(VC_IFCPath)" in MSVC
function(add_module name)
file(MAKE_DIRECTORY ${PREBUILT_MODULE_DIR})
add_custom_target(${name}.ifc
COMMAND
${CMAKE_CXX_COMPILER}
/std:c++latest
/stdIfcDir ${STD_MODULES_DIR}
/experimental:module
/c
/EHsc
/MD
${CMAKE_CURRENT_SOURCE_DIR}/${ARGN}
/module:export
/ifcOutput
${PREBUILT_MODULE_DIR}/${name}.ifc
/Fo${PREBUILT_MODULE_DIR}/${name}.obj
)
endfunction()
set(CUSTOM_MODULES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/modules)
add_module(my_module ${CUSTOM_MODULES_DIR}/my_module.ixx)
add_executable(test
test.cpp
)
target_compile_options(test
BEFORE
PRIVATE
/std:c++latest
/experimental:module
/stdIfcDir ${STD_MODULES_DIR}
/ifcSearchDir ${PREBUILT_MODULE_DIR}
/reference my_module=${PREBUILT_MODULE_DIR}/my_module.ifc
/EHsc
/MD
)
target_link_libraries(test ${PREBUILT_MODULE_DIR}/my_module.obj)
add_dependencies(test my_module.ifc)
With C++20 Modules the file compilation order matters, which is totally new. That's why the implementation is complicated and still experimental in 2023. Please read the authors blogpost
I was not able to find Cmake support for modules. Here is an example how to use modules using clang. I am using Mac and this example works ok on my system. It took me quite a while to figure this out so unsure how general this is across linux or Windows.
Source code in file driver.cxx
import hello;
int main() { say_hello("Modules"); }
Source code in file hello.cxx
#include <iostream>
module hello;
void say_hello(const char *n) {
std::cout << "Hello, " << n << "!" << std::endl;
}
Source code in file hello.mxx
export module hello;
export void say_hello (const char* name);
And to compile the code with above source files, here are command lines on terminal
clang++ \
-std=c++2a \
-fmodules-ts \
--precompile \
-x c++-module \
-Xclang -fmodules-embed-all-files \
-Xclang -fmodules-codegen \
-Xclang -fmodules-debuginfo \
-o hello.pcm hello.mxx
clang++ -std=c++2a -fmodules-ts -o hello.pcm.o -c hello.pcm
clang++ -std=c++2a -fmodules-ts -x c++ -o hello.o \
-fmodule-file=hello.pcm -c hello.cxx
clang++ -std=c++2a -fmodules-ts -x c++ -o driver.o \
-fmodule-file=hello=hello.pcm -c driver.cxx
clang++ -o hello hello.pcm.o driver.o hello.o
and to get clean start on next compile
rm -f *.o
rm -f hello
rm -f hello.pcm
expected output
./hello
Hello, Modules!
Hope this helps, all the best.
I have a fresh install of OS X 10.11.4 that I immediately installed the Xcode toolchain on, then Homebrew, then Boost 1.60. In order to test that everything had gone well, I wrote the following code on my Desktop.
#include <iostream>
#include <boost/filesystem.hpp>
int main() {
boost::filesystem::path new_directory("hello");
boost::filesystem::create_directory(new_directory);
}
I then attempted to compile it as I usually have done with the following command.
$ clang++ test.cpp -o test -lboost_system -lboost_filesystem
I received the following error.
test.cpp:3:10: fatal error: 'boost/filesystem.hpp' file not found
#include <boost/filesystem.hpp>
This is how I have always compiled projects that link Boost in the past. I'm assuming that I have probably forgotten a step along the way that allows clang to search a specific path to dynamically link the libraries. What should I change in order for this compilation command to work?
For me, boost has been compiled and installed into a subdirectory of my home directory, so you'll need to modify the paths as appropriate for your homebrew installation:
flags="-std=c++1z -I/${HOME}/local/include -L${HOME}/local/lib -lboost_filesystem -lboost_system"
c++ ${flags} -o jared jared.cpp
First get the location of boost by doing the following:
brew info boost
From the image above, you can see that my location is
/usr/local/Cellar/boost/1.66.0
Then, to compile, use the following:
c++ -I /usr/local/Cellar/boost/1.66.0 main.cpp -o boost
I am trying to compile the following code which has the headers:
#include <SDL2/SDL.h>
#include <SDL2_image/SDL_image.h>
However after running the following makefile:
g++ -std=c++11 src/main.cpp -lSDL2 -lSDL2_image
I get the following error:
fatal error: SDL2_image/SDL_image.h: No such file or directory
#include <SDL2_image/SDL_image.h>
Any suggestions? Not entirely sure about my installation of SDL_image. I am running this on Ubuntu.
This problem can be solved through installing libsdl2-image-dev package:
apt install libsdl2-image-dev
Run apt-file search SDL_image.h
The result will tell you the location of the include file.
For instance, /usr/include/SDL2/SDL_image.h was returned.
So, when you want to include SDL_image.h, write everything after the include/ in between < >.
Thus, includes should look like the following:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
See the question's comments for the original discussion regarding this solution.
From SDL documentation, it says that add 'lSDL_image' to the end of the compile line.
cc -o myprogram mysource.o `sdl-config --libs` -lSDL_image
or
gcc -o myprogram mysource.c `sdl-config --libs` -lSDL_image
Here is the reference -> https://www.libsdl.org/projects/docs/SDL_image/SDL_image.html
Section 2.2 Compiling.
So for SDL2, you just need to change 'lSDL_image' to 'lSDL2_image'.
For Windows + SDL2-2.0.8 + SDL_image-2.0.4 + Codeblocks you've got the add both Runtime Binaries and Development Libraries to the compiler and linker. Or else, you'll get the error SDL2_image not found, even with having the dll in your program's directory, this occurs. Hopefully others find this helpful; I had to figure it out myself. Example: If your resources are separate, you'll be adding the two plus your standard SDL2 paths to your compiler and linker. Warning: SDL2_image.h has it's headers assuming that the headers are in the same folder as the SDL2 framework. If you get errors about the image header, include the sub-folder SDL2 from SDL framework in the path and then you should be including SDL2 in the program as: include <SDL.h> rather than include <SDL2/SDL.h>.
While trying to compile the boost asio example project
async_tcp_echo_server.cpp
I get errors like the following:
__MSABI_LONG was not declared in this file scope
BOOST_ASIO_NATIVE_ERROR(ERROR_BROKEN_PIPE)
__MSABI_LONG was not declared in this file scope
BOOST_ASIO_NATIVE_ERROR(ERROR_OPERATION ABORTED)
This is with Boost 1.55.0 and gcc version 4.8.3
boost was compiled with gcc and the following commands
./bootstrap.sh
./b2 cxxflags="-D__USE_W32_SOCKETS -D_WIN32_WINNT=0x0501
./b2 install
I attempted to compile the sample project with
gcc -std=C++11 -D__USE_W32_SOCKETS -D_WIN32_WINNT=0x0501 -I C:\boost_1_55_0 C:\boost_1_55_0\boost\asio.hpp async_tcp_echo_server.cpp
I know this is kind of old thread.
I managed to fix it by reinstalling the boost lib via Cygwin setup_x86.exe.
The version I installed is 1.57. And you don't have to put -D option in the command line.
Hope this may help.
1_57 version from cygwin setup doesn't help for me, it gives me fd_set errors.
This is what I tried to make the boost example code work:
add #define __MSABI_LONG(x) x at the top. - chilly, I know :)
add these flags to g++:-D_WIN32_WINNT=0x0501 -D__USE_W32_SOCKETS -std=c++11 -lboost_system -lws2_32
Voila!
I'm trying to add something to a larger C++ project which is developed using CMake. In the part I'm adding, I want to use Magick++.
If I'm only compiling my small example program
#include <Magick++.h>
int main()
{
Magick::Image image;
return 0;
}
with
g++ -o example example.cxx
it fails since it doesn't find "Magick++.h".
If I'm using
g++ -I /usr/include/ImageMagick -o example example.cxx
I get "undefined reference" errors.
If I follow the instructions on http://www.imagemagick.org/script/magick++.php and compile using
g++ `Magick++-config --cxxflags --cppflags` -o example example.cxx `Magick++-config --ldflags --libs`
it works.
Now:
How do I incorporate this into the larger project that uses CMake? How do I have to change the CMakeLists.txt?
There is FindImageMagick.cmake module in the basic CMake distribution, so you are lucky.
You should add something like this this to the CMakeLists.txt:
find_package(ImageMagick COMPONENTS Magick++)
After that, you can use following variables:
ImageMagick_FOUND - TRUE if all components are found.
ImageMagick_INCLUDE_DIRS - Full paths to all include dirs.
ImageMagick_LIBRARIES - Full paths to all libraries.
ImageMagick_<component>_FOUND - TRUE if <component> is found.
ImageMagick_<component>_INCLUDE_DIRS - Full path to <component> include dirs.
ImageMagick_<component>_LIBRARIES
So you can do just
include_directories(${ImageMagick_INCLUDE_DIRS})
target_link_libraries(YourApp ${ImageMagick_LIBRARIES})