Google Protobuf - Protoc Compiling Proto Files with Imports - cmake

The gRPC examples show use of one proto file and one output file. However, I was supplied a protofile that imports another, which in turn imports several from another directory.
Is the protoc supposed to produce headers and source files from the imported files? Or do you need to run the compiler on every single individual proto file?
Does anyone have an example cmake, where the proto files import?
I've got something like this in my cmake to compile one proto file:
add_custom_command(
OUTPUT "${chat_proto_srcs}" "${chat_proto_hdrs}" "${chat_grpc_srcs}" "${chat_grpc_hdrs}"
COMMAND ${PROTOC_COMPILER}
ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}"
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
-I "${chat_proto_path}"
--plugin=protoc-gen-grpc="${GRPC_PLUGIN}"
"${chat_proto}"
DEPENDS "${chat_proto}")
But it doesn't seem to produce anything for any files that are imported from the file pointed to by ${chat_proto}
I've also tried:
# Generated Proto files
file(GLOB_RECURSE proto_files "${CMAKE_CURRENT_SOURCE_DIR}/*.proto")
PROTOBUF_GENERATE_CPP(proto_srcs proto_hdrs ${proto_files} PLUGIN protoc-gen-grpc=${GRPC_PLUGIN})
add_custom_target(proto_dep DEPENDS ${proto_srcs} ${proto_hdrs})
message(STATUS "Generated source files are ${proto_srcs}")
However, I do not see any .grpc.pb.cc files or know how to get the list of them to add to compilation of my library with add_library. If I understand the docs correctly, I have to compile the *.pb.cc files as well as the *.grpc.pb.cc files.

Related

How do I generate PDB files using cmake and gcc?

I want to use the OpenCppCoverage to check the coverage of my source files by my Unit Test. However, it seems that I need to have .pdb files generated for OpenCppCoverage to work.
The problem is that I am not being able to generate such files from my build. Here is my CmakeLists.txt
cmake_minimum_required(VERSION 3.17) # version can be different
project(GUnitTestingVSCode) #name of your project
add_subdirectory(googletest) # add googletest subdirectory
add_compile_definitions(TELEMETRY_DIAGNOSTICS)
add_compile_definitions(GTEST)
set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/")
include_directories(googletest/include/) # this is so we can #include <gtest/gtest.h>
include_directories(googletest/googlemock/include/gmock/) # this is so we can #include <gmock/gmock.h>
include_directories("${CMAKE_SOURCE_DIR}/"
"${CMAKE_SOURCE_DIR}/inc/"
"${CMAKE_SOURCE_DIR}/mocks/"
"${CMAKE_SOURCE_DIR}/../submodule/library/inc"
"${CMAKE_SOURCE_DIR}/../submodule/library/inc/Application"
"${CMAKE_SOURCE_DIR}/../submodule/library/inc/Datalink/"
"${CMAKE_SOURCE_DIR}/../submodule/library/inc/Demodulation"
"${CMAKE_SOURCE_DIR}/../submodule/library/inc/Modulation"
"${CMAKE_SOURCE_DIR}/../inc/Peripherals/"
"${CMAKE_SOURCE_DIR}/../inc/Protocol/"
"${CMAKE_SOURCE_DIR}/../inc/Diagnostics/")
file(GLOB_RECURSE SOURCES RELATIVE
${CMAKE_SOURCE_DIR} "../src/Peripherals/DMA.c" "../src/Diagnostics.c"
${CMAKE_SOURCE_DIR} "../src/Protocol/DataLink.c"
"src/*.cpp" "googletest/*.cpp" "mocks/*.c"
"../submodule/library/src/*.c")
add_executable(gUnitTest ${SOURCES}) # add this executable
set(CMAKE_BUILD_TYPE RelWithDebInfo)
set_target_properties(gUnitTest PROPERTIES
COMPILE_PDB_NAME "gUnitTestCompiled"
COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/"
PDB_NAME "gUnitTestLinker"
PDB_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/")
target_link_libraries(gUnitTest PUBLIC gtest gmock) # link google test to this executable
However, when I build my Test folder in RelWithDebInfo mode (I also tried Debug), I get no .pdb files in the build folder. Can someone help me understand what am I doing wrong?
The compiler used is GCC 9.2.0 (mingw32)
I was able to figure out myself. So here is the answer if someone struggles with the same:
gcc compiler is not able to generate .pdb files. What can be done is the following:
Convert the debug information from gcc to pdb files using the converter called cv2pdb
Use llvm/clange compiler that has support to generate .pdb
Use another code coverage tool, such as gcov from gcc itself
I decided to use option 3, and replace opencppcoverage by gcov (in fact I am using gcovr). I had to include the extra flags for coverage as mentioned above:
-fprofile-arcs -ftest-coverage -fPIC -O0

Ninja Make system not accepting GENERATED command

I have a set of assembly files which should be compiled by a special compiler. After this it should be added to the library created by the compiler i have set in CMAKE_C_COMPILER. it was working fine with Mingw Makefile system but not working with Ninja Make.
Below is the code in cmakelists.txt
add_custom_target(
special_asm
COMMAND
${SPECIAL_ASM} ${src_file1}
-I${INCLUDE_PATH} -o file1.o
COMMAND
${SPECIAL_ASM} ${src_file2}
-I${INCLUDE_PATH} -o file2.o
)
add_custom_target(special_asm_cmd COMMAND cmd.exe special_asm*.bat)
add_dependencies(special_asm_cmd special_asm)
add_library(
mylib STATIC
file1.o
file2.o
${mylib_src})
add_dependencies(mylib special_asm_cmd)
set_source_files_properties(
file1.o
file2.o
PROPERTIES EXTERNAL_OBJECT true GENERATED true)
file1.o and file2.o are generated by different assembler. i have set the properties for these files also.
Problem 1:
custom target special_asm is not directly generating the object files. It is generating a batch script. That's why i have created one more custom target called special_asm_cmd to run the batch script which will generate the object files. The Mingw make system was directly generating the object file from special_asm but Ninja is not doing like that.
Problem 2
I have set the property GENERATED true for the special generated object files. But ninja is giving the below error. But Mingw Make was able to solve the dependency and no errors
ninja: error: '<path>/spt_init.o', needed by '<path>/libmylib.a', missing and no known rule to make it
There's no point in using GENERATED here - cmake will know it, when you tell him, how you generate the files anyway.
add_custom_command(
# Put generated files in binary dir, where they belong
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/file1.o
# Enumerate all dependencies.
DEPENDS
${src_file1}
${INCLUDE_PATH}/header1.h ${INCLUDE_PATH}/header2.h etc..
COMMAND
${SPECIAL_ASM} ${src_file1} -I${INCLUDE_PATH}
-o ${CMAKE_CURRENT_BINARY_DIR}/file1.o
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/file2.o
DEPENDS
${src_file2}
${INCLUDE_PATH}/header1.h ${INCLUDE_PATH}/header2.h etc..
COMMAND
${SPECIAL_ASM} ${src_file2}
-I${INCLUDE_PATH}
-o ${CMAKE_CURRENT_BINARY_DIR}/file2.o
)
add_custom_target(special_asm_cmd
# Enumerate the dependencies.
DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/file2.o
${CMAKE_CURRENT_BINARY_DIR}/file1.o
# Glob in add_custom target? Use glob with `file(GLOB ...`
COMMAND cmd.exe special_asm*.bat
)
add_library(mylib STATIC
${CMAKE_CURRENT_BINARY_DIR}/file2.o
${CMAKE_CURRENT_BINARY_DIR}/file1.o
${mylib_src}
)
Cmake is a build system, specifically designed to know what comes from what. Files comes from other files plus commands. Tell cmake what files come from which commands and which source files - cmake will manage the dependencies and do all the rest like parallelizing the work and proper dependency tracking.

Compile headers for errors using cmake

Background
I have a number of headers as part of a library (call it A) and are also used externally from other libraries (call it C).
I'd like to compile as part A's compilation to ensure the headers are self-contained. (Currently, this involves compiling C and if there are issues, re-compile A & make a new release).
Question
What's the best way to compile headers and discard the results? I am only interested in their successful compilation.
I am thinking of copy and rename them as cpp files (it's a C++ project) and then create a library out of them to check errors. But is there a simpler solution?
My aim is to the command-line equivalent of
g++ [compile_flags] -c header.hpp
and check for errors but not interested in the produced files.
I'd like something that works with cmake 3.13.5 (or older).
Thanks
Since I ran into the same question recently, let me show the solution I went with:
When you list the header files in your target's sources and only use relative paths below the current path (i.e. no .. in the paths), you can use a function like the following to compile a separate cpp file for each hpp file.
function(check_headers target)
# build object library used to "compile" the headers
add_library(${target}_headers OBJECT)
target_link_libraries(${target}_headers PRIVATE ${target})
target_include_directories(${target}_headers PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
# add a proxy source file for each header in the target source list
get_target_property(TARGET_SOURCES ${target} SOURCES)
foreach(TARGET_SOURCE ${TARGET_SOURCES})
if ("${TARGET_SOURCE}" MATCHES ".*\.hpp$")
set(HEADER_SOURCEFILE "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_SOURCE}.cpp")
file(WRITE "${HEADER_SOURCEFILE}" "#include \"${TARGET_SOURCE}\"")
target_sources(${target}_headers PRIVATE "${HEADER_SOURCEFILE}")
endif()
endforeach()
endfunction()
It adds an object library that compiles each header file in the given target.

How to include generated files for compilation with cmake?

I have a set of .xsd files in a subdirectory 'xsd'. I generate a set of .hxx and cxx files for XML-binding with an external command.
add_custom_command(
PRE_BUILD
OUTPUT ${PROJECT_SOURCE_DIR}/xsd/file1.hxx ${PROJECT_SOURCE_DIR}/xsd/file1.cxx
COMMAND ${XSD_EXECUTABLE} cxx-tree
--file-list-prologue 'set(XSD_GENERATED_FILES '
--file-list ${PROJECT_SOURCE_DIR}/cmake_xsd_filelist.txt
--file-list-epilogue ')'
--output-dir ${PROJECT_SOURCE_DIR}/xsd
${XSD_SOURCE_FILES}
DEPENDS ${XSD_SOURCE_FILES}
)
The tool creates a list of generated files. I have it in the following form:
set(XSD_GENERATED_FILES
file1.cpp
file1.hpp
file2.cpp
file2.hpp
)
Fine up to here.
Now the part where I don't know how to continue. I want to include the generated file list and add them to the executable.
include(${PROJECT_SOURCE_DIR}/cmake_xsd_filelist.txt)
add_executable(Prog ${SOURCE_FILES} ${XSD_GENERATED_FILES})
But this does not do what I want. Actually, it does nothing because initially cmake_xsd_filelist.txt is empty.
My goal is the following:
when a file in the 'xsd' folder changes, execute XSD_EXECUTABLE for generating the .cpp and hpp files.
only compile once the generated .cpp files when they have changed
add the generated source files to the executable.
Is this even possible with cmake? If yes, how?
Include sources
include(${PROJECT_SOURCE_DIR}/cmake_xsd_filelist.txt)
add_executable(Prog ${SOURCE_FILES} ${XSD_GENERATED_FILES})
This means that you need to have a cmake_xsd_filelist.txt file on configure step, i.e. xsd must be invoked by execute_process. Also I think it's better to generate files to binary directory (follow out-of-source concept):
# Create directory if needed
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/generated")
execute_process(
COMMAND
${XSD_EXECUTABLE} cxx-tree
--file-list-prologue 'set(XSD_GENERATED_FILES '
--file-list "${CMAKE_BINARY_DIR}/generated/cmake_xsd_filelist.txt"
--file-list-epilogue ')'
--output-dir "${CMAKE_BINARY_DIR}/generated/xsd"
${XSD_SOURCE_FILES}
RESULT_VARIABLE result
)
Do not forget to check successfull exit status:
if(NOT result EQUAL 0)
message(FATAL_ERROR "XSD failed")
endif()
Now you can include sources:
include(${CMAKE_BINARY_DIR}/generated/cmake_xsd_filelist.txt)
add_executable(Prog ${SOURCE_FILES} ${XSD_GENERATED_FILES})
XSD sources update
when a file in the 'xsd' folder changes, execute XSD_EXECUTABLE
for generating the .cpp and hpp files.
I.e. CMake must run reconfigure if one of the xsd file changes. Here is the trick that helps:
foreach(x ${XSD_SOURCE_FILES})
configure_file(${x} ${x} COPYONLY)
endforeach()
Now if any of the XSD_SOURCE_FILES changes CMake will reconfigure the project effectively re-running XSD_EXECUTABLE and re-including cmake_xsd_filelist.txt.

CMake Compiling Generated Files

I have a list of files that get generated during the CMake build process. I want to compile these files using "add_library" afterward, but I won't know which files get generated until after they get generated. Is there anyway to build this into a CMake script?
Well, I think it is possible, so I'll share what I've done. My problem was that I had to compile several CORBA idls to use as part of a project's source and I didn't want to manually list every file. I thought it would be better to find the files. So I did it like this:
file(GLOB IDLS "idls/*.idl")
set(ACE_ROOT ${CMAKE_FIND_ROOT_PATH}/ace/ACE-${ACE_VERSION})
foreach(GENERATE_IDL ${IDLS})
get_filename_component(IDLNAME ${GENERATE_IDL} NAME_WE)
set(OUT_NAME ${CMAKE_CURRENT_SOURCE_DIR}/idls_out/${IDLNAME})
list(APPEND IDL_COMPILED_FILES ${OUT_NAME}C.h ${OUT_NAME}C.cpp ${OUT_NAME}S.h ${OUT_NAME}S.cpp)
add_custom_command(OUTPUT ${OUT_NAME}C.h ${OUT_NAME}C.cpp ${OUT_NAME}S.h ${OUT_NAME}S.cpp
COMMAND ${ACE_ROOT}/bin/tao_idl -g ${ACE_ROOT}/bin/ace_gperf -Sci -Ssi -Wb,export_macro=TAO_Export -Wb,export_include=${ACE_ROOT}/include/tao/TAO_Export.h -Wb,pre_include=${ACE_ROOT}/include/ace/pre.h -Wb,post_include=${ACE_ROOT}/include/ace/post.h -I${ACE_ROOT}/include/tao -I${CMAKE_CURRENT_SOURCE_DIR} ${GENERATE_IDL} -o ${CMAKE_CURRENT_SOURCE_DIR}/idls_out/
COMMENT "Compiling ${GENERATE_IDL}")
endforeach(GENERATE_IDL)
set_source_files_properties(${IDL_COMPILED_FILES}
PROPERTIES GENERATED TRUE)
set(TARGET_NAME ${PROJECT_NAME}${DEBUG_SUFFIX})
add_executable(
${TARGET_NAME}
${SOURCE}
${IDL_COMPILED_FILES}
)
The GENERATED properties is useful in case one of my idl compilation outputs (*C.cpp, *C.h, *S.cpp and *S.h) is not created, so that the build command doesn't complain that the file doesn't exist.
Well, it is possible to do so with CMake's CMAKE_CONFIGURE_DEPENDS directory property. This forces CMake to reconfigure if any of the given files changed.
Simple solution
The following code shows the approach for a single model file, that is used as input for the code generation:
set(MODEL_FILE your_model_file)
set_directory_properties(PROPERTIES CMAKE_CONFIGURE_DEPENDS ${MODEL_FILE})
set(GENERATED_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/${MODEL_FILE})
file(REMOVE_RECURSE ${GENERATED_SOURCE_DIR})
file(MAKE_DIRECTORY ${GENERATED_SOURCE_DIR})
execute_process(COMMAND your_code_generation_tool -o ${GENERATED_SOURCE_DIR} ${MODEL_FILE})
file(GLOB LIBGENERATED_FILES ${GENERATED_SOURCE_DIR}/*)
add_library(libgenerated ${LIBGENERATED_FILES})
target_include_directories(libgenerated ${GENERATED_SOURCE_DIR})
With the above approach, each time the model file has changed CMake will reconfigure which results in the model being regenerated.
Advanced solution
The problem with the simple solution is that even for the smallest possible change in the model the entire dependencies of the generated files have to be rebuilt.
The advanced approach uses CMake's copy_if_different feature to let only generated files that are affected by the model change to appear modified which results in better build times. To achieve that we use a staging directory as destination for the generator and sync the contents subsequently with the generator output of the previous compile run:
set(MODEL_FILE your_model_file)
set(GENERATOR_STAGING_DIR ${CMAKE_CURRENT_BINARY_DIR}/${MODEL_FILE}.staging)
set(GENERATOR_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/${MODEL_FILE})
set_directory_properties(PROPERTIES CMAKE_CONFIGURE_DEPENDS ${MODEL_FILE})
# Create fresh staging/final output directory
file(REMOVE_RECURSE ${GENERATOR_STAGING_DIR})
file(MAKE_DIRECTORY ${GENERATOR_STAGING_DIR})
file(MAKE_DIRECTORY ${GENERATOR_OUTPUT_DIR})
# Run code generation
execute_process(COMMAND your_code_generation_tool -o ${GENERATOR_STAGING_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_FILE}")
# Remove stale files from final generator output directory
file(GLOB GENERATED_FILES RELATIVE "${GENERATOR_OUTPUT_DIR}/" "${GENERATOR_OUTPUT_DIR}/*")
foreach(FILE ${GENERATED_FILES})
if(NOT EXISTS "${GENERATOR_STAGING_DIR}/${FILE}")
file(REMOVE "${GENERATOR_OUTPUT_DIR}/${FILE}")
endif()
endforeach()
# Copy modified files from staging to final generator output directory
file(GLOB GENERATED_FILES RELATIVE "${GENERATOR_STAGING_DIR}/" "${GENERATOR_STAGING_DIR}/*")
foreach(FILE ${GENERATED_FILES})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${GENERATOR_STAGING_DIR}/${FILE}" "${GENERATOR_OUTPUT_DIR}")
endforeach()
file(GLOB LIBGENERATED_FILES "${GENERATOR_OUTPUT_DIR}/*")
add_library(libgenerated ${LIBGENERATED_FILES})
target_include_directories(libgenerated PUBLIC ${GENERATOR_OUTPUT_DIR})
If you don't know the name of the files that will be generated, you can "glob" the folders where they reside.
file( GLOB_RECURSE MY_SRC dest_folder/*.cpp )
add_library( libname SHARED ${MY_SRC} )
Now I'm not sure what triggers the generation of these files. The "globbing" will happen only when you manually run cmake: it will not be able to detect automatically that new files are present.
Treat this as a non-answer, just more info:
I recently had to do something for one case where I had a .cpp file that was auto-generated, but I could not figure out how to get CMake to construct the Visual Studio project file that would then compile it. I had to resort to something quite stinky: I had to #include <the_generated.cpp> file from another file that resided under the ${CMAKE_CURRENT_SOURCE} directory. That won't help you much in your case because I suspect you have several .cpp files, so this approach is not scalable.
Also, I found that the GENERATED source file property, when added to the file, did not help at all.
I consider this condition either a bug in Visual Studio (in my case this was VS2008 SP1), or in how CMake generates the .vcproj files, or both.