Cmake for Custom Library Build System in Go
In the previous post, I implemented a Go shim layer that enables c++ codes to use Go functionalities. This post dives a little bit deeper into CMake build system for this interaction.
The following CMakeLists.txt provides a binary compilation altogether with compiling Go based static library.
cmake_minimum_required(VERSION 3.0)
project(test)
set(TARGET_OUT test.out)
set(TARGET_LIB test.lib)
# Go configurations
set(GO_SRCS
test.go)
set(GO_LIBNAME libtest.a)
# Custom command for 'go build -buildmode=c-archive ...'
# to create a library from Go codes.
add_custom_command(OUTPUT ${GO_LIBNAME}
DEPENDS ${GO_SRCS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND env go build -buildmode=c-archive
-o "${CMAKE_CURRENT_BINARY_DIR}/${GO_LIBNAME}"
${CMAKE_GO_FLAGS} ${GO_SRCS}
COMMENT "Building Go library")
# Add a custom target for the library.
add_custom_target(${TARGET_LIB} DEPENDS ${GO_LIBNAME})
# C++ configurations
set(CPP_SRCS
test.cpp)
# A library and a header are generated in the binary directory.
include_directories(${CMAKE_CURRENT_BINARY_DIR})
link_directories(${CMAKE_CURRENT_BINARY_DIR})
add_executable(${TARGET_OUT} ${CPP_SRCS})
add_dependencies(${TARGET_OUT} ${TARGET_LIB})
target_link_libraries(${TARGET_OUT} test pthread)
We want to divide Go compilation from c++ build, hence regard them as seperate CMake projects.
Directory structure is as follows.
$ tree .
.
├── CMakeLists.txt
├── go
│ ├── CMakeLists.txt
│ ├── go.mod
│ └── test.go
└── test.cpp
Two CMakeLists.txt look:
# c++ cmake configuration
cmake_minimum_required(VERSION 3.0)
project(test)
add_subdirectory(go)
set(TARGET test.out)
set(SRCS test.cpp)
add_executable(${TARGET} ${SRCS})
add_dependencies(${TARGET} goshim)
target_link_libraries(${TARGET} goshim pthread)
# Go cmake configuration
cmake_minimum_required(VERSION 3.0)
project(test_go)
find_library(golang REQUIRED)
set(TARGET shim_go)
set(GOPATH ${CMAKE_CURRENT_BINARY_DIR})
set(SRCS test.go)
set(LIB libgoshim.a)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${LIB}
DEPENDS ${SRCS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND env GOPATH=${GOPATH} go build -buildmode=c-archive
-o "${CMAKE_CURRENT_BINARY_DIR}/${LIB}"
${CMAKE_GO_FLAGS} ./...
COMMENT "Building Go library")
add_custom_target(${TARGET} DEPENDS ${LIB} ${HEADER})
add_library(goshim STATIC IMPORTED GLOBAL)
add_dependencies(goshim ${TARGET})
set_target_properties(goshim
PROPERTIES
IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/${LIB}
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR})
CMakeLists.txt for Go is based on the post in Stackoverflow1.
The key part is add_library(IMPORTED)
2, to tell the library is not generated by CMake system and use the library located outside the project.
With IMPORTED_LOCATION
and INTERFACE_INCLUDE_DIRECTORIES
, CMake can detect where the library (.a or .so) and headers (.h) are.
The library (libgoshim.a) and the header (libgoshim.h) are generated in ${CMAKE_CURRENT_BINARY_DIR}/go
, but CMakeLists.txt for c++ does not have to explicitly include this directory. Therefore, CMakeLists.txt is kept simple as above, but at the same time can use target_link_libraries(${TARGET} goshim
from C++ cmake, thanks to the command add_library(IMPORTED)
from Go cmake.
$ make
Scanning dependencies of target shim_go
[ 33%] Building Go library
[ 33%] Built target shim_go
Scanning dependencies of target test.out
[ 66%] Building CXX object CMakeFiles/test.out.dir/test.cpp.o
[100%] Linking CXX executable test.out
[100%] Built target test.out
$ ./test.out
Hello from c++!
Hello from Go!
-
custom target as a target library in cmake: https://stackoverflow.com/q/31274577 ↩︎
-
Imported Libraries: https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries ↩︎