CMake compile glsl shaders - cmake

I am adapting Sascha Willems' Vulkan Samples to compile shaders when ever i build the program. I know this question has been asked a lot but none of the solutions I found worked for me.
Here is my code:
cmake_minimum_required(VERSION 3.19)
project(Test)
set( ${CMAKE_CURRENT_SOURCE_DIR}/shaders)
set(SHADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/shaders)
file(GLOB SHADERS ${SHADER_DIR}/*.vert ${SHADER_DIR}/*.frag ${SHADER_DIR}/*.comp ${SHADER_DIR}/*.geom ${SHADER_DIR}/*.tesc ${SHADER_DIR}/*.tese ${SHADER_DIR}/*.mesh ${SHADER_DIR}/*.task ${SHADER_DIR}/*.rgen ${SHADER_DIR}/*.rchit ${SHADER_DIR}/*.rmiss)
file(GLOB SPV_SHADERS ${SHADER_DIR}/*.spv)
find_package(Vulkan)
foreach(SHADER IN LISTS SHADERS)
get_filename_component(FILENAME ${SHADER} NAME)
add_custom_command(OUTPUT ${SHADER_DIR}/shaders/${FILENAME}.spv
COMMAND ${Vulkan_GLSLC_EXECUTABLE} ${SHADER} -o ${SHADER_DIR}/shaders/${FILENAME}.spv
DEPENDS ${SHADER}
COMMENT "Compiling ${FILENAME}")
endForeach()
add_custom_target(shaders ALL DEPENDS ${SPV_SHADERS})
add_executable(Test main.cpp ${SHADERS})
add_dependencies(Test shaders)
[Edit]: CMake seems to skip the foreach loop am I using it correctly?
[Edit2]: Now the loop works but the shaders are still not compiling

After searching a bit, I deleted file(GLOB SPV_SHADERS ${SHADER_DIR}/*.spv) and replaced it with list(APPEND SPV_SHADERS ${ASSETS_DIR}/shaders/${FILENAME}.spv)
It would look like this:
cmake_minimum_required(VERSION 3.19)
project(Test)
set( ${CMAKE_CURRENT_SOURCE_DIR}/shaders)
set(SHADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/shaders)
file(GLOB SHADERS ${SHADER_DIR}/*.vert ${SHADER_DIR}/*.frag ${SHADER_DIR}/*.comp ${SHADER_DIR}/*.geom ${SHADER_DIR}/*.tesc ${SHADER_DIR}/*.tese ${SHADER_DIR}/*.mesh ${SHADER_DIR}/*.task ${SHADER_DIR}/*.rgen ${SHADER_DIR}/*.rchit ${SHADER_DIR}/*.rmiss)
find_package(Vulkan)
foreach(SHADER IN LISTS SHADERS)
get_filename_component(FILENAME ${SHADER} NAME)
add_custom_command(OUTPUT ${SHADER_DIR}/shaders/${FILENAME}.spv
COMMAND ${Vulkan_GLSLC_EXECUTABLE} ${SHADER} -o ${SHADER_DIR}/shaders/${FILENAME}.spv
DEPENDS ${SHADER}
COMMENT "Compiling ${FILENAME}")
list(APPENDS SPV_SHADERS ${SHADER_DIR}/shaders/${FILENAME}.spv)
endForeach()
add_custom_target(shaders ALL DEPENDS ${SPV_SHADERS})
add_executable(Test main.cpp ${SHADERS})
add_dependencies(Test shaders)

Related

CMake question: Two same output obj generated by VS IDE and CMake command line cause LNK4006

I am new for CMake, and I'm adding NASM files into projects by CMakelists.
With this version, IDE and project have two output folders to generate same obj, so that cause warning lnk4006 already defined second definition ignored.
One output folder and it is like build\encoder\x86.
Another is like build\encoder\x86\xxxenc_x86_asm.dir\Debug\ or build\encoder\x86\xxxenc_x86_asm.dir\Release.
I have trid to update the second output path to be same with the first, but it can't work.
CMakelists like following:
add_library(${ENCODER_X86_ASM_LIB_NAME} OBJECT "")
if ((LINUX OR MACOSX OR WIN32) AND ${ENABLE_ASM})
set(ASM_EXECUTABLE "${NASM_EXE}")
if(CMAKE_GENERATOR STREQUAL "Xcode")
add_library(${ENCODER_NATIVE_ASM_LIB_NAME} INTERFACE)
endif()
set(X86_ASM_SRCS
asm/avx2/average_avx2.asm)
if (WIN32)
set(ASM_FLAGS ...)
elseif(MACOSX)
set(ASM_FLAGS -I${PROJECT_SOURCE_DIR}/ -f macho64 -O2 -DARCH_X86_64=1 -DPREFIX -DOS_MAC=1 -DPIC -Worphan-labels -DSTACK_ALIGNMENT=16)
elseif(LINUX)
set(ASM_FLAGS -I${PROJECT_SOURCE_DIR}/ -f elf64 -O2 -DARCH_X86_64=1 -DOS_MAC=0 -DPIC -Worphan-labels -DSTACK_ALIGNMENT=16)
endif()
#generate objects when building CMake
if(CMAKE_GENERATOR STREQUAL "Xcode")
asm_compile_to_target(${ENCODER_NATIVE_ASM_LIB_NAME} ${X86_ASM_SRCS})
else()
asm_compile_to_target(${ENCODER_X86_ASM_LIB_NAME} ${X86_ASM_SRCS})
endif()
if ((MACOSX AND (CMAKE_GENERATOR STREQUAL "Xcode")) OR WIN32)
foreach(asm_file ${X86_ASM_SRCS})
set(ASM_SRC ${CMAKE_CURRENT_LIST_DIR}/${asm_file})
get_filename_component(filename "${asm_file}" NAME_WE)
set(ASM_OBJ "${CMAKE_CURRENT_BINARY_DIR}/${filename}${CMAKE_C_OUTPUT_EXTENSION}")
list(APPEND ASM_SRCS ${ASM_SRC})
list(APPEND ASM_OBJS ${ASM_OBJ})
add_custom_command(
OUTPUT ${ASM_OBJ}
COMMAND ${ASM_EXECUTABLE}
ARGS ${ASM_FLAGS} ${ASM_SRC} -o ${ASM_OBJ}
DEPENDS ${ASM_SRC}
)
endforeach()
foreach(OBJ ${ASM_OBJS})
list(APPEND ASM_PRIMITIVES ${OBJ})
endforeach()
foreach(SRC ${X86_ASM_SRCS})
list(APPEND ASM_PRIMITIVES ${CMAKE_CURRENT_LIST_DIR}/${SRC})
endforeach()
source_group(Assembly FILES ${ASM_PRIMITIVES})
if(CMAKE_GENERATOR STREQUAL "Xcode")
target_sources(${ENCODER_NATIVE_ASM_LIB_NAME} INTERFACE ${ASM_PRIMITIVES})
else()
target_sources(${ENCODER_X86_ASM_LIB_NAME} PRIVATE ${ASM_PRIMITIVES})
endif()
if (MACOSX)
add_custom_target(${ENCODER_X86_ASM_LIB_NAME}-asm ALL DEPENDS ${ASM_PRIMITIVES})
target_sources(${ENCODER_X86_ASM_LIB_NAME} INTERFACE ${ASM_PRIMITIVES})
add_dependencies(${ENCODER_X86_ASM_LIB_NAME} ${ENCODER_X86_ASM_LIB_NAME}-asm)
else()
target_sources(${ENCODER_X86_ASM_LIB_NAME} PRIVATE ${ASM_PRIMITIVES})
endif()
endif() ## if ((MACOSX) AND (CMAKE_GENERATOR STREQUAL "Xcode") OR WIN32)
endif() ## if ((LINUX OR MACOSX OR WIN32) AND ${ENABLE_AVX2})
target_compile_definitions(${ENCODER_X86_ASM_LIB_NAME} PUBLIC)
Here, CMAKE_CURRENT_BINARY_DIR is one output folder and it is build\encoder\x86.
how to deal with this issue?
Background is this: we need to support incremental compiling in IDE, also need to support building by cmake command line.
I have tried to update output path(or directory) as:
set_target_properties(${ENCODER_X86_ASM_LIB_NAME} PROPERTIES LIBRARY_OUTPUT_PATH ${PATH} )
set_target_properties(${ENCODER_X86_ASM_LIB_NAME} PROPERTIES BUILD_RPATH ${PATH} )
set_target_properties(${ENCODER_X86_ASM_LIB_NAME} PROPERTIES INSTALL_RPATH ${PATH} )
set_target_properties(${ENCODER_X86_ASM_LIB_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PATH} )
It just can't work.
Thanks!

What is a correct way to solve undefined reference to undefined reference to `LLVMInitializeAArch64TargetInfo'

In Clion when i build llvm project I got following message:
CMakeFiles/codegen_llvm.dir/main.cpp.o: In function `llvm::InitializeAllTargetInfos()':
/usr/lib/llvm-9/include/llvm/Config/Targets.def:26: undefined reference to `LLVMInitializeAArch64TargetInfo'
/usr/lib/llvm-9/include/llvm/Config/Targets.def:27: undefined reference to `LLVMInitializeAMDGPUTargetInfo'
/usr/lib/llvm-9/include/llvm/Config/Targets.def:28: undefined reference to `LLVMInitializeARMTargetInfo'
/usr/lib/llvm-9/include/llvm/Config/Targets.def:29: undefined reference to `LLVMInitializeBPFTargetInfo'
/usr/lib/llvm-9/include/llvm/Config/Targets.def:30: undefined reference to `LLVMInitializeHexagonTargetInfo'
/usr/lib/llvm-9/include/llvm/Config/Targets.def:31: undefined reference to `LLVMInitializeLanaiTargetInfo'
And My CmakeLists is here:
cmake_minimum_required(VERSION 3.15)
project(codegen_llvm)
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
set(CMAKE_CXX_STANDARD 14)
add_executable(codegen_llvm main.cpp)
llvm_map_components_to_libnames(llvm_libs support core irreader executionEngine)
target_link_libraries(codegen_llvm ${llvm_libs})
...
What should I do?
cmake solution
cmake_minimum_required(VERSION 3.10)
project(project_name )
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
link_libraries()
execute_process(COMMAND llvm-config --libs OUTPUT_VARIABLE LIBS)
execute_process(COMMAND llvm-config --system-libs OUTPUT_VARIABLE SYS_LIBS)
execute_process(COMMAND llvm-config --ldflags OUTPUT_VARIABLE LDF)
#message(STATUS "Found LLVM" ${LIBS})
string(STRIP ${LIBS} LIBS)
string(STRIP ${SYS_LIBS} SYS_LIBS)
string(STRIP ${LDF} LDF)
link_libraries(${LIBS} ${SYS_LIBS} ${LDF})
execute_process(COMMAND llvm-config --cxxflags OUTPUT_VARIABLE CMAKE_CXX_FLAGS)
string(STRIP ${CMAKE_CXX_FLAGS} CMAKE_CXX_FLAGS)
add_executable(project_name toy.cpp)
one liner
clang++ -g toy.cpp $(llvm-config --cxxflags --ldflags --system-libs --libs) -O3 -o toy
If you still do not have a solution for this error, try to add ${LLVM_TARGETS_TO_BUILD} to your link libraries.
I am using CLion too, and I solved this by changing:
llvm_map_components_to_libnames(llvm_libs support core irreader codegen mc mcparser option)
to:
llvm_map_components_to_libnames(llvm_libs ${LLVM_TARGETS_TO_BUILD} support core irreader codegen mc mcparser option)
In your last but one line config is not an llvm component, so you'd want to remove it. To see the list of official components, use the llvm-config --components command.

How to reload cmake targets

Following is the my scenario. I have one top level CMakeList.txt and another 2 internal CMakeList.txt. In top level cmake I have 3 custom targets that are copy, build, copyandbuild. As name specifies make copy copies the source directories (i.e dir1, dir2) to ${CMAKE_SOURCE_DIR}. make build creates libs and executables. make copyandbuild (copy+build).
Running cmake .. from build directory completes successfully.
If I run make copyandbuild it is copying to ${CMAKE_SOURCE_DIR} but at the time of build it is showing error that
No rule to make target `dir1/libmylib.so', needed by `CMaketargetdbuild'. Stop
MyProject
dir1
CMakeLists.txt
dir2
CMakeLists.txt
CMakeLists.txt
It is working if i execute commands in below order.
cmake ..
make copyandbuild
cmake ..
make build
My requirement is it should work with out running cmake and make build again as copyandbuild doing the same work.
Top level CMakeLists.txt:
cmake_minimum_required(VERSION 2.6)
cmake_minimum_required(VERSION 2.6)
set(RE_BUILD make rebuild_cache)
set(OUTPUT_DIR ${CMAKE_SOURCE_DIR}/../)
if(EXISTS ${CMAKE_SOURCE_DIR}/dir1)
message(WARNING "Found dir1 dir")
add_subdirectory(dir1 EXCLUDE_FROM_ALL)
else()
message(WARNING "Couldn't find dir1 directory ")
endif()
if(EXISTS ${CMAKE_SOURCE_DIR}/dir2)
add_subdirectory(dir2 EXCLUDE_FROM_ALL)
else()
message(WARNING "Couldn't find dir2 directory")
endif()
set(MOVE_LIB_COMMAND mv src/myapp . && mv dir1/mylib .)
set(COPY_COMMAND cp -r ../sourceCode1 ../dir1 && cp -r ../sourceCode2 ../dir2)
set(CLEAN_DIR1_COMMAND cmake -E remove_directory ${CMAKE_SOURCE_DIR}/dir1)
set(CLEAN_DIR2_COMMAND cmake -E remove_directory ${CMAKE_SOURCE_DIR}/dir2)
set(SET_SLEEP sync)
#Copy command
add_custom_target(
copy ${COPY_COMMAND}
COMMAND ${RE_BUILD}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
#Compilation
add_custom_target(
build
COMMAND ${MOVE_LIB_COMMAND}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS mylib myapp
)
#copy and compile
add_custom_target(
copyandbuild
COMMAND ${MOVE_LIB_COMMAND}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS copy mylib myapp
)
add_custom_command(TARGET copy POST_BUILD
COMMAND ${SET_SLEEP}
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
dir1 CMake is :
cmake_minimum_required(VERSION 2.6)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
include_directories(
${MY_APP_INCLUDE_DIRS}
)
link_directories(
${MY_APP_LIBDIR}
)
add_library(mylib
SHARED
com/*.cpp
)
target_link_libraries(mylib myapp_lib)
dir2 CMake is :
cmake_minimum_required(VERSION 2.6)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
include_directories(
${MY_APP_INCLUDE_DIRS}
)
link_directories(
${MY_APP_LIBDIR}
)
You are using CMake in a way that prevents its proper function. By explicitly invoking shell commands in many places, when you could use CMake built in features, you are robbing CMake of any context that it could use to build your programs. Also, using wildcards like *.cpp in CMake is considered bad practice. And you have a number of duplicate statements--you do not need cmake_minimum_required() or setting compiler flags other than at the top level.
In short, your CMakeLists.txt at the top level should look more like this:
cmake_minimum_required(VERSION 2.6)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
add_subdirectory(dir1 EXCLUDE_FROM_ALL)
You should not need to copy source files around--just build them from where they are, for example your dir1/CMakeLists.txt might be:
add_library(mylib
SHARED
sourceCode1/mylib.cpp
)
Keep it simple. Get it working. Then ask questions if you need to add missing features.

PROTOBUF_GENERATE_CPP not generating src and header files

My cmake configuration is not generating any protobuf src and header files.
I've already checked if the proto files can be found.
Cmakelists.txt
cmake_minimum_required(VERSION 3.0.2)
..
include(FindProtobuf REQUIRED)
file(GLOB PROTO_DEF "${CMAKE_CURRENT_SOURCE_DIR}/protobuf/*/*.proto")
foreach(file ${PROTO_DEF})
if(EXISTS ${file})
MESSAGE("YES")
else()
MESSAGE("NO")
endif()
endforeach()
SET(PROTOBUF_GENERATE_CPP_APPEND_PATH PROTOBUF)
SET(PROTOBUF_PROTOC_EXECUTABLE protoc.exe)
..
PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_INCL ${PROTO_DEF})
..
add_library(${PROJECT_NAME} STATIC ${INCLUDES} ${INTERNAL_INCLUDES} ${SRC} ${PROTO_SRC} ${PROTO_INCL})
target_link_libraries(${PROJECT_NAME} ${PROTOBUF_LIBRARIES})
I have checked the FindProtobuf.cmake and half way through:
foreach(FIL ${ARGN})
get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
get_filename_component(FIL_WE ${FIL} NAME_WE)
list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc")
list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h")
MESSAGE(1 ${CMAKE_CURRENT_BINARY_DIR})
MESSAGE(2 ${_protobuf_include_path})
MESSAGE(3 ${ABS_FIL})
MESSAGE(4 ${PROTOBUF_PROTOC_EXECUTABLE})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc"
"${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h"
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL}
DEPENDS ${ABS_FIL}
COMMENT "Running C++ protocol buffer compiler on ${FIL}"
VERBATIM )
endforeach()
You can see i've added the 4 message commands, the script reaches this point and variables show good values.
The proto files do have a depencency to the library, thus the command should get executed !?
Any ideas on this problem?
update
replacing the add_custom_command with
EXEC_PROGRAM(${PROTOBUF_PROTOC_EXECUTABLE} ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL}
does generate the source and header files, must i manually activate the custom_commmands?
Regards Auke
The add_custom_command is fired (for my project) during compilation time.
Adding
SET_SOURCE_FILES_PROPERTIES(${PROTO_SRC} ${PROTO_INCL} PROPERTIES GENERATED TRUE)
gives cmake info that the files will be generated.
Alternative if you have an external proto folder:
file(GLOB PROTOBUF_FILELIST ${PROTO_INCLUDE_DIR}/*.proto)
foreach( proto_file ${PROTOBUF_FILELIST} )
get_filename_component(proto_name ${proto_file} NAME_WE)
get_filename_component(proto_path ${PROTO_INCLUDE_DIR} ABSOLUTE)
set_source_files_properties("${proto_path}/${proto_name}.pb.cc"
"${proto_path}/${proto_name}.pb.h"
PROPERTIES GENERATED TRUE)
endforeach()
See that:
https://cmake.org/cmake/help/v3.20/module/FindProtobuf.html
Example:
find_package(Protobuf REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS foo.proto)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS EXPORT_MACRO DLL_EXPORT foo.proto)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS DESCRIPTORS PROTO_DESCS foo.proto)
protobuf_generate_python(PROTO_PY foo.proto)
add_executable(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS})
target_link_libraries(bar ${Protobuf_LIBRARIES})
Note The protobuf_generate_cpp and protobuf_generate_python functions and add_executable() or add_library() calls only work properly within the same directory.
This problem only happens when the target is a library (using add_library, add_executable seems to be fine). The PROTOBUF_GENERATE_CPP will defer the generation of protobuf sources and headers when building the library. A workaround is to define a custom target and add it as a dependency to the lib target. e.g.
add_custom_target(proto_dep DEPENDS ${PROTO_SRCS} ${PROTO_HDRS})
add_library(${PROJECT_NAME} STATIC ${OTHER_SRCS})
add_dependencies(${PROJECT_NAME} proto_dep)
target_link_libraries(${PROJECT_NAME} PRIVATE gRPC::grpc++ gRPC::grpc++_reflection protobuf::libprotobuf)

How to stop CMake from linking against libstdc++

I have a very simple CMakeLists.txt for a C++ project, which builds a shared library:
add_library(foo SHARED
${HDR_PUBLIC}
${SOURCES})
When linking the library, CMake automatically uses -lstdc++. How can I stop it from doing this?
You can add -stdlib=libc++ to compiler flags.
Simple example:
cmake_minimum_required(VERSION 2.8.4)
project(test)
set(CMAKE_VERBOSE_MAKEFILE TRUE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -v -stdlib=libc++")
add_executable(test main.cpp)
Give output:
"/usr/bin/ld" ... -o test ... -lc++ ...
By default:
cmake_minimum_required(VERSION 2.8.4)
project(test)
set(CMAKE_VERBOSE_MAKEFILE TRUE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -v")
add_executable(test main.cpp)
Link to stdc++:
"/usr/bin/ld" ... -o test ... -lstdc++ ...
[update]
If you don't need to link to c++ lib at all - use '-nodefaultlibs' as linker flag and '-nostdinc++' to compiler flag. You may need to link some default libraries, like '-lSystem'.
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "")
set_target_properties(yourtarget PROPERTIES LINKER_LANGUAGE C)
Source: http://cmake.3232098.n2.nabble.com/setting-LINKER-LANGUAGE-still-adds-lstdc-td7581940.html