CMake: add_subdirectory twice as a shared project - cmake

I've search the internet all over, but there is no simple answer for the issue.
I've read this: CMake: Attempted to add link library to target which is not built in this directory
But i don't want to put the target_link_libraries into the same cmake list, instead i want to leave the linkage commands inside each respective list because a library cmake list has to know which one library dependency it must be linked with.
Mine project's structure is this:
<main_exe> : /main
| : |
<main_lib> : +- /_3dparty
/ \ : | |
<lib_A> <lib_B> : | +- /lib_A/CMakeLists.txt
\ / : | +- /lib_B/CMakeLists.txt
<lib_X> : | +- /lib_X/CMakeLists.txt
: |
: +- /CMakeLists.txt
All 3 libraries are standalone and static, and i don't want to make them as a subdirectory to each other.
But when i tried to add_subdirectory with external binary directory from lib_A and lib_B respectively:
if (NOT TARGET lib_X)
add_subdirectory(${lib_X_ROOT} ${CMAKE_BUILD_ROOT}/_3dparty/lib_X)
endif()
add_dependencies(${PROJECT_NAME} lib_X)
target_link_libraries(${PROJECT_NAME}
PUBLIC
lib_X
)
, then the cmake throw an error:
Attempt to add link library "lib_X" to target "lib_B" which is not built in
this directory
Is there a way to put it to work w/o excessive ExternalProject_Add usage?
EDIT:
I reproduced the issue on the minimal example.
The library libB actually had slightly different structure:
/main
|
+- /_3dparty
| |
| +- /lib_A/CMakeLists.txt
| +- /lib_B
| | |
| | +- /libsubdir/CMakeLists.txt
| | +- /CMakeLists.txt
| |
| +- /lib_X/CMakeLists.txt
|
+- /CMakeLists.txt
That was the cause of the issue.
/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(main_project)
set(CMAKE_BUILD_ROOT ${CMAKE_CURRENT_LIST_DIR}/_build)
set(CMAKE_LIBS_ROOT ${CMAKE_CURRENT_LIST_DIR}/_3dparty)
add_library(mainlib ${CMAKE_CURRENT_LIST_DIR}/main.cpp)
add_subdirectory(${CMAKE_LIBS_ROOT}/libA ${CMAKE_BUILD_ROOT}/_3party/libA)
add_subdirectory(${CMAKE_LIBS_ROOT}/libB ${CMAKE_BUILD_ROOT}/_3party/libB)
target_link_libraries(mainlib
PUBLIC
libA
libB
)
/_3dparty/libA/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(libA_project)
add_library(libA STATIC ${CMAKE_CURRENT_LIST_DIR}/main.cpp)
add_subdirectory(${CMAKE_LIBS_ROOT}/libX ${CMAKE_BUILD_ROOT}/_3party/libX)
target_link_libraries(libA
PUBLIC
libX
)
/_3dparty/libB/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(libB_project)
#add_library(libB STATIC ${CMAKE_CURRENT_LIST_DIR}/libsubdir/main.cpp)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/libsubdir) # the root cause of the issue
#add_subdirectory(${CMAKE_LIBS_ROOT}/libX ${CMAKE_BUILD_ROOT}/_3party/libX) # would be an error if add this twice
target_link_libraries(libB # <- the issue error is here
PUBLIC
libX
)
/_3dparty/libB/libsubdir/CMakeLists.txt
add_library(libB STATIC main.cpp)
/_3dparty/libX/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(libX_project)
add_library(libX STATIC ${CMAKE_CURRENT_LIST_DIR}/main.cpp)
Output:
x:\_cmake_test\_out>cmake .. -G "Visual Studio 14 2015"
CMake Error at _3dparty/libB/CMakeLists.txt:11 (target_link_libraries):
Attempt to add link library "libX" to target "libB" which is not built in
this directory.
-- Configuring incomplete, errors occurred!
See also "X:/_cmake_test/_out/CMakeFiles/CMakeOutput.log".
If uncomment the add_library(libB ... and comment add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/libsubdir) then the issue disappears.
Any suggestions how to fix that w/o edit a 3dparty library?

Do not do add_subdirectory() in cmake-projects which are likely to be used as sub-directories itself.
Instead create a super-project which does all the add_subdirectory() at the same level (in the same CMakeLists.txt). The order is not important, CMake resolves the target-dependency (done via target_link_libraries()) once all CMakeLists.txt have been processed.
This is an approach I ended up using in all my projects. It has some disadvantages, for example unit-testing of each library might be difficult, but this is solvable with conditioning the tests with a variable.

Related

How to configure a subdirectory project in CMake in a way that find_package in another one is able to find it?

I am trying to build the netCDF C++ library as a dependency to my project on Windows 10 using MSVC shipped with VS2017 (I think v141 but not sure). Since some of the dependencies I will mention below require CMake > 3.12 I am forced to use CMake that is not shipped with VS2017. The problem is that netCDF C++ requires the netCDF C library (I guess the former is a wrapper for the latter), which in terms depends on the HDF5 library.
All can be found on github as CMake projects:
https://github.com/HDFGroup/hdf5
https://github.com/Unidata/netcdf-c
https://github.com/Unidata/netcdf-cxx4
Currently my project's structure is as follows:
MAIN PROJECT
|
*--- CMakeLists.txt
|
*--- examples (CMake subproject)
| |
| *---CMakeLists.txt
| |
| *--- example1 (CMake subproject, uses my_library)
| |
| *--- example2 (CMake subproject, uses my_library)
|
*--- deps (CMake subproject)
| |
| *--- CMakeLists.txt
| |
| *--- jsoncpp (CMake subproject, git clone)
| |
| *--- ...
| |
| *--- hdf5 (CMake subproject, git clone)
| |
| *--- netcdf-c (CMake subproject, git clone)
| |
| *--- netcdf-cxx4 (CMake subproject, git clone)
|
*--- my_library (CMake subproject, my own library that uses deps)
|
*--- my_binary (CMake subproject, my own executable that uses my_library and deps)
Until I started tinkering with netCDF I didn't have any issues. My deps CMakeLists.txt look like this:
add_subdirectory(sqlite3)
set(JSONCPP_WITH_EXAMPLE OFF CACHE BOOL "Compile JsonCpp example")
set(JSONCPP_WITH_TESTS OFF CACHE BOOL "Compile and (for jsoncpp_check) run JsonCpp test executables")
set(JSONCPP_WITH_POST_BUILD_UNITTEST OFF CACHE BOOL "Automatically run unit-tests as a post build step")
set(BUILD_STATIC_LIBS ON CACHE BOOL "Build jsoncpp_lib as a static library.")
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build jsoncpp_lib as a shared library.")
add_subdirectory(jsoncpp)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries")
set(BUILD_CURL_EXE OFF CACHE BOOL "Build curl EXE")
add_definitions("-DCURL_STATICLIB")
if(WIN32)
set(ENABLE_UNICODE OFF CACHE BOOL "Set to ON to use the Unicode version of the Windows API functions")
endif()
add_subdirectory(curl)
add_subdirectory(hdf5)
add_subdirectory(netcdf-c) # ISSUE with find_package and hdf5
add_subdirectory(netcdf-cxx4)
The netcdf-c subproject has the following lines, which cause a problem for me:
IF(MSVC)
SET(SEARCH_PACKAGE_NAME ${HDF5_PACKAGE_NAME})
FIND_PACKAGE(HDF5 NAMES ${SEARCH_PACKAGE_NAME} COMPONENTS C HL CONFIG REQUIRED ${NC_HDF5_LINK_TYPE})
ELSE(MSVC)
FIND_PACKAGE(HDF5 COMPONENTS C HL REQUIRED)
ENDIF(MSVC)
From what I saw the same applies to netcdf-cxx4 so solving this can hopefully be applied to it too.
I do not want to touch anything inside the respective dependenies' folders (I plan on adding those as git submodules later on). Is there a way to instruct the underlying sub-project (just like a did for e.g. JSON++) where to look without installing anything from the project one level up? Possibly a useful note here is that I also don't have any install() calls.

How to structure a cmake project with different 3rd-party libraries

I'm new with cmake and try to create a small project which needs some 3rd-party libs. I would like to have the libs as git repos to always be up-to-date. Some libs are just .cpp and .hpp files (glad, imgui) and others are cmake projects (glfw, glm).
The idea is to have a 3rd-party project with all the libs as a kind of subprojects and a sandbox project which uses the libs and includes etc.
And I would like to use modern cmake code which is not installing something outside the framework structure.
Folder structure:
Framework
|--3rd_party
| |--glad
| | |--include
| | |--src
| |--glfw-master
| | |--...
| | |--CMakeLists.txt
| |--glm-master
| | |--..
| | |--CMakeLists.txt
| |--imgui-master
| | |--*.cpp
| | |--*.hpp
| | |--examples
| | | |--*.cpp
| | | |--*.hpp
| |--CMakeLists.txt
|--sandbox
| |--main.cpp
| |--CMakeLists.txt
|--CMakeLists.txt
So I created this folder structure and also some CMakeLists:
CMakeLists.txt (Framework)
cmake_minimum_required(VERSION 3.10)
project(Framework)
add_subdirectory("3rd_party")
add_subdirectory("sandbox")
CMakeLists.txt (3rd_party)
#GLFW
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
add_subdirectory(glfw-master)
# GLM
set(GLM_TEST_ENABLE OFF CACHE BOOL "" FORCE)
add_subdirectory(glm-master)
# Glad
add_library(
Glad STATIC
"glad/src/glad.c"
)
target_include_directories(Glad PUBLIC "glad/include")
# ImGui
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD=1)
set(IMGUI_SOURCES
"imgui-master/imgui.cpp"
"imgui-master/imgui_demo.cpp"
"imgui-master/imgui_draw.cpp"
"imgui-master/imgui_widgets.cpp"
"imgui-master/examples/imgui_impl_glfw.cpp"
"imgui-master/examples/imgui_impl_opengl3.cpp"
)
set(IMGUI_HEADERS
"imgui-master/imconfig.h"
"imgui-master/imgui.h"
"imgui-master/imgui_internal.h"
"imgui-master/imstb_rectpack.h"
"imgui-master/imstb_textedit.h"
"imgui-master/imstb_truetype.h"
"imgui-master/examples/imgui_impl_glfw.h"
"imgui-master/examples/imgui_impl_opengl3.h"
)
add_library(
ImGui STATIC
${IMGUI_SOURCES}
${IMGUI_HEADERS}
)
target_include_directories(ImGui PUBLIC "imgui-master" "glfw-master/include" "glad/include")
CMakeLists.txt (sandbox)
project(Sandbox)
find_package(OpenGL REQUIRED)
add_executable(sandbox main.cpp)
# OpenGL
target_include_directories(Sandbox PUBLIC ${OPENGL_INCLUDE_DIR})
target_include_directories(Sandbox PUBLIC external)
# Glfw
target_include_directories(Sandbox PUBLIC "../3rd_party/glfw-master/include")
# Link libs
target_link_libraries(Sandbox PUBLIC
${OPENGL_LIBRARIES}
"../3rd_party/glfw-master/src/Debug/glfw3"
Glad
ImGui
glm_static
)
The code works but not as I expect. At first I know it's a little bit ugly maybe there is a better way to handle the path for includes and sources but the bigger problem is project structure.
For example, when I build it for ms vs studio I have three solutions
./framework.sln
./sandbox/sandbox.sln
./3rd_party/glfw-master/glfw.sln
And glad, glm and imgui are part of sandbox.sln
What I would like to have is a solution with two sub-solutions sandbox and 3rd_party which also has sub-solutions or projects for all the libs.
So is it possible at all and if yes how can I create such a structure with cmake?
After further investigation and a lot of try and error with CMake, I guess I started with wrong expectations and some missunderstandings.
It is not possible to get a useful solution/project structure for Visual Studio from CMake files because all CMake-projects will result in a VS-solution and all add_library or add_executable will be a VS-project. If I want to create a CMake-project for my framework and add GLFW as third party, which also creates a CMake-project, it will end with two different VS-solutions and bang the structure is gone. I think that is why Microsoft introduced a special open context for CMake files in Visual Studio.
If a project is opened with this context, the "solution" viewer shows the folder structure of the project. And that is more or less what I expected in the beginning.
There is also an option to switch the view to see all CMake targets (exec, libs, ...).
I also "upgraded" my CMakeLists. I use different ways to add the third party libs:
add_subdirectory for libs with CMakeLists like GLFW
add_library and INTERFACE for header-only libs like glm
add_library STATIC for static libs like ImGui (in my case)
The includes for Sandbox are provided by the public interface of the libs and the build/dependency order is given by order in target_link_libraries.
I hope that is was helpul and will spare you a lot of time ;)
Cheers!
boss0r
CMakeLists.txt (Framework)
cmake_minimum_required(VERSION 3.10)
project(OpenGL_Framework
VERSION 0.0.1
LANGUAGES CXX C # C for GLFW
)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_subdirectory(ThirdParty)
add_subdirectory(Sandbox)
CMakeLists.txt (3rd_party)
# GLFW
set(GLFW_LIB_NAME "GLFW")
set(GLFW_INC_PATH ${GLFW_LIB_NAME}/include)
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
#set(GLFW_VULKAN_STATIC OFF CACHE BOOL "" FORCE) # OFF by default
#set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) # OFF by default
set(GLFW_INSTALL OFF CACHE BOOL "" FORCE)
add_subdirectory(${GLFW_LIB_NAME})
# spdlog
set(SPDLOG_LIB_NAME "spdlog")
set(SPDLOG_MASTER_PROJECT OFF CACHE BOOL "" FORCE)
add_subdirectory(${SPDLOG_LIB_NAME})
# OR
#set(SPDLOG_LIB_NAME "spdlog")
#set(SPDLOG_SRC_PATH ${SPDLOG_LIB_NAME}/src)
#set(SPDLOG_INC_PATH ${SPDLOG_LIB_NAME}/include)
#add_library(${SPDLOG_LIB_NAME}
# STATIC
# ${SPDLOG_SRC_PATH}/spdlog.cpp
#)
#target_include_directories(${SPDLOG_LIB_NAME}
# PUBLIC
# ${SPDLOG_INC_PATH})
# glm
set(GLM_LIB_NAME "glm")
set(GLM_INC_PATH ${GLM_LIB_NAME}/glm)
add_library(${GLM_LIB_NAME} INTERFACE)
target_include_directories(${GLM_LIB_NAME}
INTERFACE
${GLM_INC_PATH}
)
# OR
#set(GLM_LIB_NAME "glm")
#set(GLM_INC_PATH ${GLM_LIB_NAME}/glm)
#set(GLM_TEST_ENABLE OFF CACHE BOOL "" FORCE)
#add_subdirectory(${GLM_LIB_NAME})
#target_include_directories(${GLM_LIB_NAME}
# PUBLIC
# $(GLM_INC_PATH)
#)
# Glad
set(GLAD_LIB_NAME "Glad")
set(GLAD_SRC_PATH "${GLAD_LIB_NAME}/src")
set(GLAD_INC_PATH "${GLAD_LIB_NAME}/include")
add_library( ${GLAD_LIB_NAME}
STATIC
"${GLAD_SRC_PATH}/glad.c"
)
target_include_directories(${GLAD_LIB_NAME}
PUBLIC
"${GLAD_INC_PATH}"
)
# ImGui
set(IMGUI_LIB_NAME "ImGui")
set(IMGUI_SOURCES
"${IMGUI_LIB_NAME}/imgui.cpp"
"${IMGUI_LIB_NAME}/imgui_demo.cpp"
"${IMGUI_LIB_NAME}/imgui_draw.cpp"
"${IMGUI_LIB_NAME}/imgui_widgets.cpp"
"${IMGUI_LIB_NAME}/examples/imgui_impl_glfw.cpp"
"${IMGUI_LIB_NAME}/examples/imgui_impl_opengl3.cpp"
)
set(IMGUI_HEADERS
"${IMGUI_LIB_NAME}/imconfig.h"
"${IMGUI_LIB_NAME}/imgui.h"
"${IMGUI_LIB_NAME}/imgui_internal.h"
"${IMGUI_LIB_NAME}/imstb_rectpack.h"
"${IMGUI_LIB_NAME}/imstb_textedit.h"
"${IMGUI_LIB_NAME}/imstb_truetype.h"
"${IMGUI_LIB_NAME}/examples/imgui_impl_glfw.h"
"${IMGUI_LIB_NAME}/examples/imgui_impl_opengl3.h"
)
set(IMGUI_INC_PATH "${IMGUI_LIB_NAME}/")
add_library(${IMGUI_LIB_NAME}
STATIC
${IMGUI_SOURCES}
${IMGUI_HEADERS}
)
target_compile_definitions(${IMGUI_LIB_NAME}
PRIVATE
IMGUI_IMPL_OPENGL_LOADER_GLAD=1
)
target_include_directories(${IMGUI_LIB_NAME}
PUBLIC
"${IMGUI_INC_PATH}"
"${GLFW_INC_PATH}"
"${GLAD_INC_PATH}"
)
CMakeLists.txt (sandbox)
project(Sandbox)
find_package(OpenGL REQUIRED)
add_executable(${PROJECT_NAME} Sandbox.cpp)
target_include_directories(${PROJECT_NAME}
PUBLIC
external
${OPENGL_INCLUDE_DIR}
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
${OPENGL_gl_LIBRARY}
glfw
Glad
ImGui
glm
#glm_static # if build with add_subdirectory
spdlog::spdlog
)

How to add C++REST SDK as a submodule with CMake?

I am trying to build a project with numerous dependencies such as Boost, OpenSSL, and C++ REST SDK. However, it is required that the source code is included in the project workspace and that the library is built from said source code.
The most consistently successful way I have found to achieve this is though the use of git submodule add <URL>, add_subdirectory, target_link_libraries, and some clever projects built for this purpose such as boost-cmake and openssl-cmake.
Take for example the following project structure:
prjct
| include/
| libs/
| | boost-cmake/
| | openssl-cmake/
| | cpprestsdk/
| src/
| tests/
| CMakeLists.txt
For which the top-level CMakeLists.txt would contain:
...
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/boost-cmake)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/openssl-cmake)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/cpprestsdk)
target_link_libraries(${PROJECT_NAME_L}
PUBLIC
Boost::system
Boost::thread
Boost::log
Boost::program_options
Boost::chrono
ssl # OpenSSL::SSL
crypto # OpenSSL::Crypto
cpprestsdk::cpprest
)
...
However, in the case of the cpprestsdk library, I recieve the following error upon running cmake .. from build/:
CMake Error at CMakeLists.txt:55 (add_library):
Target "prjct" links to target "cpprestsdk::cpprest" but the target
was not found. Perhaps a find_package() call is missing for and IMPORTED
target, or an ALIAS target is missing?
How can I link and use the C++ REST SDK within these constraints?

How to set include_directories from a CMakeLists.txt file?

I seem to be having trouble setting the include path (-I) using the include_directories() command in CMake. My project directory is as follows:
Root
| - CMakeLists.txt
| - libs
| - | - CMakeLists.txt
| - | - inc
| - | - | - // lib specific includes
| - | - src
| - | - | - // lib specific sources
| - proj1
| - | - CMakeLists.txt
| - | - inc
| - | - | - // proj1 specific includes
| - | - src
| - | - | - // proj1 specific sources
The root CMakeLists.txt file looks like so:
project(ROOT)
add_subdirectory(libs)
add_subdirectory(proj1)
The CMakeLists.txt file under libs:
project(lib)
add_library(lib STATIC ${lib_hdrs} ${lib_srcs}) // for conciseness, omitted set()
And lastly, the CMakeLists.txt file under proj1:
project(proj1)
include_directories("${ROOT_SOURCE_DIR}/lib/inc") # <- problem line?
add_executable(proj1 ${proj1_srcs})
target_link_libraries(proj1 lib)
The goal is to create the library from the source and header files in libs, then link against the executable generated under proj1. Proj1 has some files that #include stuff in libs include, so I need to add the directories to be used with -I. Based on the documentation, that's what include_directories() is supposed to do. However despite explicitly setting that and following it with a debug message(${INCLUDE_DIRECTORIES}), the INCLUDE_DIRECTORIES variable is an empty string, and no directories are specified for the include path, so my compilation of proj1 fails.
I've also attempted removing the quotes around ${ROOT_SOURCE_DIR}/inc to see if that helped but no luck.
include_directories() populates a directory property called INCLUDE_DIRECTORIES:
http://www.cmake.org/cmake/help/v2.8.12/cmake.html#prop_dir:INCLUDE_DIRECTORIES
Note that CMake 2.8.11 learned the target_include_directories command, which populates the INCLUDE_DIRECTORIES target property.
http://www.cmake.org/cmake/help/v2.8.12/cmake.html#command:target_include_directories
Note also that you can encode the fact that 'to compile against the headers of the lib target, the include directory lib/inc is needed' into the lib target itself by using target_include_directories with the PUBLIC keyword.
add_library(lib STATIC ${lib_hdrs} ${lib_srcs}) # Why do you list the headers?
target_include_directories(lib PUBLIC "${ROOT_SOURCE_DIR}/lib/inc")
Note also I am assuming you don't install the lib library for others to use. In that case you would need to specify different header directories for the build location and for the installed location.
target_include_directories(lib
PUBLIC
# Headers used from source/build location:
"$<BUILD_INTERFACE:${ROOT_SOURCE_DIR}/lib/inc>"
# Headers used from installed location:
"$<INSTALL_INTERFACE:include>"
)
Anyway, that's only important if you are installing lib for others to use.
After the target_include_directories(lib ...) above you don't need the other include_directories() call. The lib target 'tells' proj1 the include directories it needs to use.
See also target_compile_defintions() and target_compile_options().

developing an llvm pass with cmake out of llvm source directory

I am trying to develop an llvm pass under my project directory. For that, I follow the info in http://llvm.org/docs/CMake.html#developing-llvm-pass-out-of-source. I create my CMakeFiles appropriately as in this link and my final project directory is like;
|-- src
| |-- CMakeLists.txt
| |-- bigForPass
| | |-- CMakeLists.txt
| | |-- bigForPass.cpp
| | |-- merged.bc
| |-- build
I also linked my source files with llvm root directory without any problem.
Finally I make the build under the 'build' folder and my shared library is created successfully with no problems (under build/bin folder) with the name LLVMHello1.dylib.
However, when I try to run my pass over merged.bc file (which contains my llvm code) with the command
opt -load ../build/bin/LLVMHello1.dylib -bishe_insert <merged.bc> final.bc
I keep getting the error;
Error opening '../build/bin/LLVMHello1.dylib': dlopen(../build/bin/LLVMHello1.dylib, 9): Symbol not found: __ZTIN4llvm10ModulePassE
Referenced from: ../build/bin/LLVMHello1.dylib
Expected in: flat namespace
in ../build/bin/LLVMHello1.dylib
-load request ignored.
Any ideas and suggestions on this appreciated ?
Thanks a lot in advance.
from http://www.jiang925.com/node/28
Undefined Symbol: _ZTIN4llvm12FunctionPassE There is an inconsistency
between LLVM main build system and the cmake support for building
out-of-source. The LLVM binaries are built without runtime type info
"-fno-rtti". Therefore, the out-of-source passes have to be built the
same way otherwise opt will complain that symbol
"_ZTIN4llvm12FunctionPassE" is undefined.
To solve this problem, LLVM must be compile with RTTI enabled. Add
"-DLLVM_REQUIRES_RTTI=1" to cmake, or add "REQUIRES_RTTI=1" to make.
So I added SET(CMAKE_CXX_FLAGS "-Wall -fno-rtti") to CMakeLists.txt of my pass library and then it's working.