Need help with cmake integration of gRPC

2,216 views
Skip to first unread message

Bill Tao

unread,
Sep 4, 2023, 9:44:10 AM9/4/23
to ns-3-users
Hi.

I am trying the implement an ns-3 emulation setup that involves gRPC. More details of this setup is covered on this thread.

However, I am currently having some trouble integrating gRPC as a 3rd party library, and any pointers would be highly appreciated.

Mostly I have followed the two approaches (find_package and FetchContent) from the gRPC git page and the example cmake files here and here. My attempted CMakeLists for these two approaches are attached below. My goal is to build the gRPC hello world example server from the ns-3 scratch dir using ns-3 toolchain. The scratch cpp file is also attached below.

I feel like I got closer with the FetchContent approach, but I am getting the following error when './ns3 configure'.
 -- Configuring done
CMake Error: install(EXPORT "ns3ExportTargets" ...) includes target "libxhaul" which requires target "grpc++_reflection" that is not in any export set.
CMake Error: install(EXPORT "ns3ExportTargets" ...) includes target "libxhaul" which requires target "grpc++" that is not in any export set.

I.e. cmake seemingly can't find the gRPC library.

The find_package approach will give more errors starting from the "absl::flags target not found".

Any input is highly appreciated. Thank you!


FindPackageApproach
FetchContentApproach
scratch-grpc.cc

Gabriel Ferreira

unread,
Sep 4, 2023, 11:43:59 AM9/4/23
to ns-3-users
Your reading of the error message is incorrect. 
It says libxhaul (your library) requires a library built by the current CMake project (fetch content just downloads a subproject and make its targets appear as parent project targets).
However, all libraries declared via the build_lib macro are automatically added to the ns3ExportTargets group, which is an essential piece for proper installation and packaging.

To solve  the problem, what you need to do is add these libraries to the export set with the following:

FetchContent_MakeAvailable(grpc) # downloads and call add_subdirectory() to parse grpc's CMake
# Add libraries to the ns-3 export set
install(
  TARGETS grpc++ grpc++_reflection
  EXPORT ns3ExportTargets
  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/
  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/
  RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}/
  PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ns3"
  PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ns3"
)

Bill Tao

unread,
Sep 4, 2023, 9:08:34 PM9/4/23
to ns-3-users
Thank you very much, Gabriel. That's some very helpful insight into what's behind build_lib ().

I added the install command as you suggested, some got some complaints from the propagated dependencies. So my current install command ended up like this:

install(
TARGETS zlibstatic grpc grpc++ grpc++_reflection address_sorting upb gpr ssl crypto
EXPORT ns3ExportTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}/
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ns3"
PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ns3"
)

Not sure if this is the canonical way, but it got me through the configuration (open to suggestions for better approaches).

However, I got errors when I tried to build this configuration. The errors vary depending on how I include the gRPC-generated files (gRPC converts protobuf interface definition to C++ interface classes in auto-generated headers and source files, which is executed in the following part of the CMakeList)
get_filename_component(hw_proto "./model/netconf/protos/helloworld.proto" ABSOLUTE)
get_filename_component(hw_proto_path "${hw_proto}" PATH)

# Generated sources
get_filename_component(proto_gen_dir "./model/netconf/proto_generated_file" ABSOLUTE)
set(hw_proto_srcs "${proto_gen_dir}/helloworld.pb.cc")
set(hw_proto_hdrs "${proto_gen_dir}/helloworld.pb.h")
set(hw_grpc_srcs "${proto_gen_dir}/helloworld.grpc.pb.cc")
set(hw_grpc_hdrs "${proto_gen_dir}/helloworld.grpc.pb.h")
add_custom_command(
OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}" "${hw_grpc_srcs}" "${hw_grpc_hdrs}"
COMMAND ${_PROTOBUF_PROTOC}
ARGS --grpc_out "${proto_gen_dir}"
--cpp_out "${proto_gen_dir}"
-I "${hw_proto_path}"
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
"${hw_proto}"
DEPENDS "${hw_proto}")

My question now is how I should include these gRPC-generated files? I tried including them as LIBRARIES_TO_LINK, but I would get undefined references to the gRPC-generated interface classes.
# hw_grpc_proto
add_library(hw_grpc_proto
${hw_grpc_srcs}
${hw_grpc_hdrs}
${hw_proto_srcs}
${hw_proto_hdrs})
target_link_libraries(hw_grpc_proto
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF})

#grpc libs
list (APPEND link_libs
${hw_grpc_proto}
absl::flags
absl::flags_parse
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF}
)
build_lib(
LIBNAME xhaul
SOURCE_FILES ${source_files}
HEADER_FILES ${header_files}
LIBRARIES_TO_LINK ${link_libs}
TEST_SOURCES ${test_sources}
)

/home/bill/Projects/ns-3-dev/scratch/scratch-grpc.cc:46: undefined reference to `helloworld::Greeter::Service::Service()'

I also tried including them as header and source files, but I don't think that should be the way. And the cmake would just lose sight of their dependencies anyway and give me complaints about the included header not existing.
#grpc libs
list (APPEND link_libs
absl::flags
absl::flags_parse
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF}
)

list (APPEND header_files
${hw_proto_hdrs}
${hw_grpc_hdrs}
)

list (APPEND source_files
${hw_proto_srcs}
${hw_grpc_srcs}
)

build_lib(
LIBNAME xhaul
SOURCE_FILES ${source_files}
HEADER_FILES ${header_files}
LIBRARIES_TO_LINK ${link_libs}
TEST_SOURCES ${test_sources}
)




Thanks again for your help!

Gabriel Ferreira

unread,
Sep 4, 2023, 9:45:47 PM9/4/23
to ns-3-users
>My question now is how I should include these gRPC-generated files? I tried including them as LIBRARIES_TO_LINK, but I would get undefined references to the gRPC-generated interface classes.
># hw_grpc_proto
>add_library(hw_grpc_proto # this is a cmake target

>   ${hw_grpc_srcs}
>   ${hw_grpc_hdrs}
>   ${hw_proto_srcs}
>   ${hw_proto_hdrs}
>)
>...

>#grpc libs
>list (APPEND link_libs
>   ${hw_grpc_proto} # this is you trying to dereference a variable with the cmake target, should be empty

>   absl::flags
>   absl::flags_parse
>   ${_REFLECTION}
>   ${_GRPC_GRPCPP}
>   ${_PROTOBUF_LIBPROTOBUF}
> )


Try removing the ${} wrapping hw_grpc_proto in linked libs and it should work.



>I also tried including them as header and source files, but I don't think that should be the way. And the cmake would just lose sight of their dependencies anyway and give me complaints about the included header not existing.

It should work. However you need to establish the dependency chain.
In your first example you clearly had a complete chain.

xhaul depends on hw_grpc_proto (remember to remove the ${})
hw_grpc_proto depends on ${hw_grpc_srcs} ${hw_grpc_hdrs} ${hw_proto_srcs} ${hw_proto_hdrs}, which are outputs from the add_custom_command
add_custom_command outputs depend on ${hw_proto}, which is a file that when altered, will trigger the custom command

If you want to add the grpc_srcs and grpc_hdrs directly to the xhaul library,  you  will need to set the dependencies manually to make its intermediate object library depend on these output files.

set_target_properties(${libxhaul-obj} PROPERTIES OBJECT_DEPENDS "${hw_grpc_srcs};${hw_grpc_hdrs};${hw_proto_srcs};${hw_proto_hdrs}")

If you are working with Xcode, we don't explicitly declare the object libraries, so try adding the dependencies directly to the shared library target.

set_target_properties(${libxhaul} PROPERTIES OBJECT_DEPENDS "${hw_grpc_srcs};${hw_grpc_hdrs};${hw_proto_srcs};${hw_proto_hdrs}")


Bill Tao

unread,
Sep 4, 2023, 10:48:11 PM9/4/23
to ns-3-users
Thank you for the prompt reply, Gabriel! That worked!
Learned a lot about cmake and a lot more to be learned.

I also needed to adjust the order of when I call the install command, as the hw_grpc_proto also needed to be added to the export set.

Attaching the full cmake here for future reference:
#Before this is the usual set header/source/test files

# grpc
# Use CMake's FetchContent module to clone gRPC at
# configure time. This makes gRPC's source code available to your project,
# similar to a git submodule.
message(STATUS "Using gRPC via add_subdirectory (FetchContent).")
include(FetchContent)
set(ABSL_ENABLE_INSTALL ON)
FetchContent_Declare(
grpc
GIT_TAG v1.57.0)
set(FETCHCONTENT_QUIET OFF)
FetchContent_MakeAvailable(grpc)

# Since FetchContent uses add_subdirectory under the hood, we can use
# the grpc targets directly from this build.
set(_PROTOBUF_LIBPROTOBUF libprotobuf)
set(_REFLECTION grpc++_reflection)
set(_PROTOBUF_PROTOC $<TARGET_FILE:protoc>)
set(_GRPC_GRPCPP grpc++)

set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:grpc_cpp_plugin>)


get_filename_component(hw_proto "./model/netconf/protos/helloworld.proto" ABSOLUTE)
get_filename_component(hw_proto_path "${hw_proto}" PATH)

# Generated sources
get_filename_component(proto_gen_dir "./model/netconf/proto_generated_file" ABSOLUTE)
set(hw_proto_srcs "${proto_gen_dir}/helloworld.pb.cc")
set(hw_proto_hdrs "${proto_gen_dir}/helloworld.pb.h")
set(hw_grpc_srcs "${proto_gen_dir}/helloworld.grpc.pb.cc")
set(hw_grpc_hdrs "${proto_gen_dir}/helloworld.grpc.pb.h")
add_custom_command(
OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}" "${hw_grpc_srcs}" "${hw_grpc_hdrs}"
COMMAND ${_PROTOBUF_PROTOC}
ARGS --grpc_out "${proto_gen_dir}"
--cpp_out "${proto_gen_dir}"
-I "${hw_proto_path}"
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
"${hw_proto}"
DEPENDS "${hw_proto}")

# hw_grpc_proto
add_library(hw_grpc_proto
${hw_grpc_srcs}
${hw_grpc_hdrs}
${hw_proto_srcs}
${hw_proto_hdrs})
target_link_libraries(hw_grpc_proto
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF})

install(
TARGETS zlibstatic grpc grpc++ grpc++_reflection address_sorting upb gpr ssl crypto hw_grpc_proto
EXPORT ns3ExportTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}/
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ns3"
PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ns3"
)

#grpc libs
list (APPEND link_libs
hw_grpc_proto
absl::flags
absl::flags_parse
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF}
)

build_lib(
LIBNAME xhaul
SOURCE_FILES ${source_files}
HEADER_FILES ${header_files}
LIBRARIES_TO_LINK ${link_libs}
TEST_SOURCES ${test_sources}
)

Bill Tao

unread,
Sep 5, 2023, 2:51:29 AM9/5/23
to ns-3-...@googlegroups.com
Hi, sorry I am back again.

Turns out it's still not quite there. The problem now is, now that the dependencies are fetched as subdirectories and built together with ns-3. The compile rule "all warnings treated as errors" applies to these dependencies too. 

The dependencies code base are not as clean regarding these warnings and when I try a clean rebuild of the project, they cause the build to exit.

For now, I am just collecting all the warnings and turn them off before the build. But I really don't like this.
add_compile_options(-Wno-error=comment)
add_compile_options(-Wno-error=attributes)
add_compile_options(-Wno-error=unused-function)
add_compile_options(-Wno-unused-variable)
add_compile_options(-Wno-error=sign-compare)
add_compile_options(-Wno-error=class-memaccess)

Is there a better way to get around this? Btw, does the add_compile_option() apply module-wide or project-wide?

Thanks again!


--
Posting to this group should follow these guidelines https://www.nsnam.org/wiki/Ns-3-users-guidelines-for-posting
---
You received this message because you are subscribed to the Google Groups "ns-3-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ns-3-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ns-3-users/f5dbfc3f-d3c9-48ba-ac2d-646fa498da0bn%40googlegroups.com.

Gabriel Ferreira

unread,
Sep 5, 2023, 8:33:33 AM9/5/23
to ns-3-users
add_compile_option applies folder-wide. All targets created after it is called, including subdirectories, will have these flags added. 
But when going to the parent scope and back down to a different module, they will stop being used. Safe to use with the current module layout.

Your other option is to apply it only for the grpc library with 

target_compile_options(grpc_library_target_name PRIVATE -Wno-error=comment) 

The "PRIVATE" property prevents these flags from being propagated to targets linked to the grpc one (a.k.a. the xhaul library).

Bill Tao

unread,
Sep 5, 2023, 9:05:51 AM9/5/23
to ns-3-...@googlegroups.com
I see. That sounds good. Thanks!

Bill Tao

unread,
Sep 8, 2023, 3:22:42 AM9/8/23
to ns-3-...@googlegroups.com
Hi. More follow-up questions...

When going with the build-as-lib approach, what is the proper way to include it in an ns3 cpp file? It seems I have only got it to work by accident but now I am working with a new proto file it doesn't work again.

I can see the built lib at ./build/lib/libns3_grpc_proto.a () but I can't figure out what goes after #include to include it. Should this be the header file name or the library name?

Thank you so much!

Gabriel Ferreira

unread,
Sep 8, 2023, 9:45:37 AM9/8/23
to ns-3-users
You either include with "../grpc_directory/header.h", which isn't idea to use from other modules, or <ns3/header.h>, if you included the header file paths to the build_lib () header files list.

Bill Tao

unread,
Sep 11, 2023, 7:58:04 AM9/11/23
to ns-3-users
Hi, Gabriel.

Sorry for more questions.

Your last reply inspired me to start implementing proper classes in my module directory (before I was testing in scratch/). However, the weird thing is I can't seem to include the grpc headers when I am in my module directory (contrib/xhaul), despite that including them in scratch/ is not an issue. I am still using the same cmake configuration as in the previous post (with the warning as error turned off), and it can get through the ./ns3 configure.

Do you have any idea what is happening here?

Also this was using the FetchContent approach. But to be honest I don't quite like this approach, so I also tried the find_package approach with pre-installed grpc. Below is my attempt with the cmake config, but it ended up with errors when linking libraries to my ns3 modules (error trace also attached below). 
#Before this is the usual set header/source/test files

add_compile_options(-Wno-error=comment)
add_compile_options(-Wno-error=attributes)
add_compile_options(-Wno-error=unused-function)
add_compile_options(-Wno-unused-variable)
add_compile_options(-Wno-error=sign-compare)
add_compile_options(-Wno-error=class-memaccess)

# grpc
find_package(Threads REQUIRED)

option(protobuf_MODULE_COMPATIBLE TRUE)
find_package(Protobuf CONFIG REQUIRED)
message(STATUS "Using protobuf ${Protobuf_VERSION}")

set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)
set(_REFLECTION gRPC::grpc++_reflection)
set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)

# Find gRPC installation
# Looks for gRPCConfig.cmake file installed by gRPC's cmake installation.
find_package(gRPC CONFIG REQUIRED)
message(STATUS "Using gRPC ${gRPC_VERSION}")
message("CMAKE_PREFIX_PATH = " ${CMAKE_PREFIX_PATH})

set(_GRPC_GRPCPP gRPC::grpc++)
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)

get_filename_component(ns3_proto "${CMAKE_CURRENT_SOURCE_DIR}/model/netconf/protos/ns3-netconf-agent.proto" ABSOLUTE)
get_filename_component(ns3_proto_path "${ns3_proto}" PATH)

# Generated sources
get_filename_component(proto_gen_dir "${CMAKE_CURRENT_SOURCE_DIR}/model/netconf/proto_generated_file/" ABSOLUTE)
set(ns3_proto_srcs "${proto_gen_dir}/ns3-netconf-agent.pb.cc")
set(ns3_proto_hdrs "${proto_gen_dir}/ns3-netconf-agent.pb.h")
set(ns3_grpc_srcs "${proto_gen_dir}/ns3-netconf-agent.grpc.pb.cc")
set(ns3_grpc_hdrs "${proto_gen_dir}/ns3-netconf-agent.grpc.pb.h")
add_custom_command(
OUTPUT "${ns3_proto_srcs}" "${ns3_proto_hdrs}" "${ns3_grpc_srcs}" "${ns3_grpc_hdrs}"
COMMAND ${_PROTOBUF_PROTOC}
ARGS --grpc_out "${proto_gen_dir}"
--cpp_out "${proto_gen_dir}"
-I "${ns3_proto_path}"
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
"${ns3_proto}"
DEPENDS "${ns3_proto}")


# ns3_grpc_proto
add_library(ns3_grpc_proto
${ns3_grpc_srcs}
${ns3_grpc_hdrs}
${ns3_proto_srcs}
${ns3_proto_hdrs})
target_link_libraries(ns3_grpc_proto
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF})

install(
TARGETS ns3_grpc_proto
# TARGETS zlibstatic grpc grpc++ grpc++_reflection address_sorting upb gpr ssl crypto ns3_grpc_proto
EXPORT ns3ExportTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}/
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ns3"
PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ns3"
)

#grpc libs
list (APPEND link_libs
ns3_grpc_proto
absl::flags
absl::flags_parse
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF}
)

build_lib(
LIBNAME xhaul
SOURCE_FILES ${source_files}
HEADER_FILES ${header_files}
LIBRARIES_TO_LINK ${link_libs}
TEST_SOURCES ${test_sources}
)

Error:
-- Configuring done
CMake Error at scratch/CMakeLists.txt:47 (add_executable):
  Target "scratch_scratch-simulator" links to target "absl::flags" but the
  target was not found.  Perhaps a find_package() call is missing for an
  IMPORTED target, or an ALIAS target is missing?
Call Stack (most recent call first):
  scratch/CMakeLists.txt:67 (create_scratch)

(And similar ones for the other libraries I try to link here)

Interestingly, the packages seem to have been detected, according to ccmake output:
 Protobuf_DIR                     /home/bill/.local/lib/cmake/protobuf
 absl_DIR                         /home/bill/.local/lib/cmake/absl
 gRPC_DIR                         /home/bill/.local/lib/cmake/grpc
 utf8_range_DIR                   /home/bill/.local/lib/cmake/utf8_range

What am I missing here?

Once again, thanks a lot for your help!


Gabriel Ferreira

unread,
Sep 11, 2023, 8:47:19 AM9/11/23
to ns-3-users
Target "scratch_scratch-simulator" links to target "absl::flags" but the
  target was not found.  Perhaps a find_package() call is missing for an
  IMPORTED target, or an ALIAS target is missing?

a.k.a. there used to be a target absl::flags when grpc was built as a submodule, but now there isn't.
You need to either use fetchmodule to build it, or import it somehow.

Bill Tao

unread,
Sep 11, 2023, 8:13:20 PM9/11/23
to ns-3-users
Thanks, Gabriel!

Deep inside the find_package(gRPC) call I can see the following line in an abslTargets.cmake file:
add_library(absl::flags STATIC IMPORTED)
If I add the GLOBAL option, the error won't trigger. So it seems like a scoping issue.
add_library(absl::flags STATIC IMPORTED GLOBAL)

The best way I can see would be to set the GLOBAL flag globally when I install gRPC, although this probably would be a question towards the gRPC devs.

Bill Tao

unread,
Sep 11, 2023, 10:02:17 PM9/11/23
to ns-3-users
I am able to set global scope for these imported targets from my module CMakeLists.txt, using
set_target_properties(absl::flags PROPERTIES IMPORTED_GLOBAL TRUE)

This got me through the ./ns3 configure.
But again, I have the same issue again, where I can include the headers for these dependencies in scratch/, but when I try including them in my contrib/xhaul/model/, I get "No such file or directory" for these headers. 

Any idea why this is happening?

Attaching my current module's cmake file below. Thanks!
CMakeLists.txt

Bill Tao

unread,
Sep 14, 2023, 9:01:55 AM9/14/23
to ns-3-users
I did a bit more testing. It seems to be the case that I can successfully link executables to the included headers but I can't link module libraries to the same included headers. I also tried adding an executable target from within my module directory, which also worked. Note this works even without adding these dependencies in build_lib ().
#grpc libs
list (APPEND link_libs
ns3_grpc_proto
# absl::flags
# absl::flags_parse
# ${_REFLECTION}
# ${_GRPC_GRPCPP}
# ${_PROTOBUF_LIBPROTOBUF}
)

So it seems cmake has handled the executable dependencies alright, but not the library dependencies.

I also tried including these dependencies with install(), but that resulted in a strange error without additional information
[cmake] -- Configuring incomplete, errors occurred!
[cmake] See also "/home/bill/Projects/ns-3-dev/build/CMakeFiles/CMakeOutput.log".
[proc] The command: /usr/bin/cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++ -S/home/bill/Projects/ns-3-dev -B/home/bill/Projects/ns-3-dev/build -G Ninja exited with code: 1

I feel like I am very close but I am quite stuck atm. So any help would be very appreciated. Thanks!

My current cmake is attached.
CMakeLists.txt

Bill Tao

unread,
Oct 10, 2023, 5:15:47 PM10/10/23
to ns-3-...@googlegroups.com
Gentle bump on the thread.

I am still trying to figure this out so any ideas are highly appreciated. Thanks!

Gabriel Ferreira

unread,
Oct 10, 2023, 9:06:02 PM10/10/23
to ns-3-users
You can either move headers to ${CMAKE_OUTPUT_DIRECTORY}/include to be able to include with #include <header>.

Or you could set this library include directory part of the target interface for all the linked targets to consume.

target_include_directories(${libxhaul} PUBLIC /path/to/headers)

Now every target linked to ${libxhaul} with have /path/to/headers as an include directory.

Gabriel Ferreira

unread,
Oct 10, 2023, 9:14:15 PM10/10/23
to ns-3-users
If you mean it isn't propagating third-party libraries linked to libxhaul to consumers, 
then something is wrong, because that is controlled by NS3_REEXPORT_THIRD_PARTY_LIBRARIES and it is enabled by default.


I'd say it should be 
#grpc libs list (APPEND link_libs ns3_grpc_proto absl::flags absl::flags_parse ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF} ) build_lib( LIBNAME xhaul SOURCE_FILES ${source_files} HEADER_FILES ${header_files} LIBRARIES_TO_LINK ${link_libs} TEST_SOURCES ${test_sources} ) build_exec( 
  EXECNAME grpc-server
  SOURCE_FILES model/netconf/grpc-server.cc
  LIBRARIES_TO_LINK ${libxhaul}
  EXECUTABLE_DIRECTORY_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/src/xhaul/
)

Gabriel Ferreira

unread,
Oct 10, 2023, 9:16:14 PM10/10/23
to ns-3-users
Garbage that is Google forums borked the entire formatting of my response.


#grpc libs list (APPEND link_libs 
    ns3_grpc_proto
    absl::flags 
    absl::flags_parse 
    ${_REFLECTION} 
    ${_GRPC_GRPCPP} 
    ${_PROTOBUF_LIBPROTOBUF}

build_lib( 
    LIBNAME xhaul 
    SOURCE_FILES ${source_files} 
    HEADER_FILES ${header_files} 
    LIBRARIES_TO_LINK ${link_libs} 
    TEST_SOURCES ${test_sources}
 ) 

build_exec(
    EXECNAME grpc-server
    SOURCE_FILES model/netconf/grpc-server.cc
    LIBRARIES_TO_LINK ${libxhaul}
    EXECUTABLE_DIRECTORY_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/src/xhaul/
)   
Message has been deleted

Bill Tao

unread,
Nov 7, 2023, 6:16:26 AM11/7/23
to ns-3-...@googlegroups.com
Hi, Gabriel.

Sorry for the super late reply. I have been occupied by other tasks and just redirected my attention back to this.

"If you mean it isn't propagating third-party libraries linked to libxhaul to consumers, " Yes, I meant this.

Unfortunately, it still doesn't work. I have created a minimal reproducible environment as a mock ns3 module. If you want, you can set up the environment on your end so you can poke around.
(You would also need to install gRPC first, as instructed by their official site: https://grpc.io/docs/languages/cpp/quickstart/)

You will see that the module builds without error. But if I uncomment the #include lines in model/grpc-test.h, the build will error out. My goal is to get that to work.

Thank you very much!

Bill Tao

unread,
Nov 29, 2023, 7:49:57 AM11/29/23
to ns-3-users
Gentle bump again to see if there is still any interest in solving this problem. Thanks!

Gabriel Ferreira

unread,
Dec 1, 2023, 3:02:54 PM12/1/23
to ns-3-users
Missing

include_directories(${proto_gen_dir})

And relative path that is bound to break stuff since we copy stuff around and might not end up in the path you think it will.
Use just the header name.

#include <helloworld.grpc.pb.h>

If you got any error pointing to 

add_library(ns3::${lib${BLIB_LIBNAME}} ALIAS ${lib${BLIB_LIBNAME}})

It is just that your module name differs from the build_lib(LIBNAME) value.
I thought there was a warning for that case, but apparently there isn't.

Bill Tao

unread,
Dec 2, 2023, 8:02:40 AM12/2/23
to ns-3-...@googlegroups.com
Thank you, Gabriel.

Adding include_directories(${proto_gen_dir}) 
gives me the following CMake error when doing ./ns3 configure.

CMake Error in contrib/grpc-test/CMakeLists.txt:
  Target "libgrpc-test" INTERFACE_INCLUDE_DIRECTORIES property contains path:

    "/home/bill/ns-3-dev/contrib/grpc-test/model/proto_generated_file"

  which is prefixed in the source directory.


However, the configure was able to complete. The issue persists though when uncommenting the #includes in the model/ files.

Gabriel Ferreira

unread,
Dec 2, 2023, 2:05:00 PM12/2/23
to ns-3-users
If it raised this error, it didn't complete. 
I know it worked just fine here. Not sure why you are having problems. 

Bill Tao

unread,
Dec 2, 2023, 5:07:27 PM12/2/23
to ns-3-...@googlegroups.com
Thanks.

Can I have your CMake file just to double check?

Gabriel Ferreira

unread,
Dec 2, 2023, 5:50:06 PM12/2/23
to ns-3-users
Sure. It is attached.

The outputs

$ ./ns3 build grpc-test
[0/2] Re-checking globbed directories...
ninja: no work to do.
Finished executing the following commands:
/mingw64/bin/cmake --build /ns-3-dev/cmake-cache -j 15 --target libgrpc-test

$ ldd ./build/contrib/grpc-test/examples/ns3-dev-grpc-test-example-default.exe | grep grpc
        libgrpc++.dll => /mingw64/bin/libgrpc++.dll (0x6cec0000)
        libgrpc++_reflection.dll => /mingw64/bin/libgrpc++_reflection.dll (0x62600000)
        libgrpc.dll => /mingw64/bin/libgrpc.dll (0x69a00000)

$ ./ns3 run grpc-test-example
[0/2] Re-checking globbed directories...
ninja: no work to do.
Server listening on 0.0.0.0:50051

$ ./test.py -s grpc-test
[0/2] Re-checking globbed directories...
ninja: no work to do.
Finished executing the following commands:
/mingw64/bin/cmake --build /ns-3-dev/cmake-cache -j 15
[0/1] PASS: TestSuite grpc-test
1 of 1 tests passed (1 passed, 0 skipped, 0 failed, 0 crashed, 0 valgrind errors)

CMakeLists.txt

Bill Tao

unread,
Dec 6, 2023, 8:27:20 PM12/6/23
to ns-3-...@googlegroups.com
Thanks Gabriel.

Good to know that it works at least on your machine.
I checked your CMakeLists, can't see any difference. 

I might go through my GRPC installation again. Another quick question, did you install your GRPC in your home/.local or system-wide?

Gabriel Ferreira

unread,
Dec 6, 2023, 9:47:14 PM12/6/23
to ns-3-users
System-wide via Msys2's Pacman (Windows). 
I've tried the debian apt, but it ships with grpc pkgconfig
 file instead of the cmake config, and I would need to change
 more stuff to make your cmakefile work... Which sort of defeats
the purpose to show that it does work as is, adding the include. 

Bill Tao

unread,
Jan 11, 2024, 3:05:39 AM1/11/24
to ns-3-...@googlegroups.com
Thanks, Gabriel.

After some more trial and error and getting some hint from you and this post I finally have a "kinda" working config.

I will list the additional changes I made below with more comments. I am treading in unknown territory here so your comments are more than welcome to shed some light why these changes would make things work.

1. I changed to gRPC from a local install to global install (under /usr/local). I am building from source though, which might already introduce some differences from your setup. This already makes generic gRPC headers work in model/grpc-test.h. But custom protobuf headers still can't be found (the helloworld.grpc.pb.h etc.).

2. Adding the "include_directories(${proto_gen_dir})" first at the location you suggested, i.e. before build_lib. This gets me the error cmake error I complained about 2 emails back. I am really not sure why you wouldn't get this error, since these file generation and inclusion are entirely controlled by this cmake file and shouldn't vary with external setup.

3. Changing the include_directories to after the build_lib, and I also had to add the custom protobuf headers to the lib headers 
build_lib(
LIBNAME grpc-test
SOURCE_FILES model/grpc-test.cc
helper/grpc-test-helper.cc
HEADER_FILES model/grpc-test.h
model/proto_generated_file/helloworld.grpc.pb.h
model/proto_generated_file/helloworld.pb.h
helper/grpc-test-helper.h
LIBRARIES_TO_LINK ${link_libs}
TEST_SOURCES test/grpc-test-test-suite.cc
${examples_as_tests_sources}
)

This gets me a working config that allows me to inlucde grpc both from example/ and model/

Attaching CMakeLists for reference. Thanks for all the helps!


CMakeLists.txt
Reply all
Reply to author
Forward
0 new messages