CMAKE三日谈-第二谈compile和link属性
我的理解,来自自己的测试得出,不要指望通过我的文章来获取芝士.
target_compile_options
target_compile_options(<target> [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
假如:target是foo
1.BEFORE这个属性是指在编译这个foo,在编译foo之前添加好,
foo编译的时候就会存在了;必须指定
2.后边的INTERFACE|PUBLIC|PRIVATE属性的作用和其他target的属性类型相同:
PUBLIC|PRIVATE ->会应用在foo的编译属性(compile_options)上,
INTERFACE|PUBLIC ->会应用在foo的接口编译属性(INTERFACE_COMPILE_OPTIONS)上,
之前搞不清这个概念,后来做了个实验:
practice:
env:
- Android
- CMake
1.现在包一个日志库,静态编译
CMakeLists.txt
文件
project(tools)
file(GLOB SRC_UTILS ${PROJECT_SOURCE_DIR}/*.cpp)
add_library(${PROJECT_NAME} STATIC ${SRC_UTILS})
target_include_directories(${PROJECT_NAME}
INTERFACE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/> $<INSTALL_INTERFACE:include>
)
target_compile_options(${PROJECT_NAME}
BEFORE
PRIVATE -DLOG_TAG="TOOLS")
message(STATUS "当前目录:${CMAKE_CURRENT_SOURCE_DIR}")
tools.cpp
文件
#include "tools.h"
void faklog(std::string str) {
unsigned int max_len = 4096;
unsigned int str_len = str.length();
for (int i = 0; i <= str_len / max_len; ++i) {
unsigned int end = i * max_len + max_len;
LOGD("%s", str.substr(i * max_len, end > str_len ? str_len : end).c_str());
}
}
tools.h
文件
#include <android/log.h>
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
2.现在创建一个binary工程引用这个工程:
CMakeLists.txt
文件
project(helloworld )
set(SRC_LIST hello.cpp)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} tools log)
target_compile_options(${PROJECT_NAME}
BEFORE
PRIVATE -DLOG_TAG="HELLO")
hello.cpp
文件
#include <stdio.h>
#include <unistd.h>
#include <android/log.h>
#include "tools.h"
#define MYLOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
int main() {
do {
MYLOGD("Hello world!");
LOGD("Hello world!");
printf("hello world!\n");
sleep(5);///sleep 1s;
} while (1);
return 0;
}
3.实验结果:
target_compile_options 注意这里的属性全部为PRIVATE,
结果为
11-28 06:08:02.740 18186-18186/? D/HELLO: Hello world! from binary
11-28 06:08:02.740 18186-18186/? D/HELLO: Hello world! from static lib
看到LOG_TAG都是来自binary
重新修改静态库的PRIVATE为PUBLIC—>
11-28 06:38:17.900 12479-12479/? D/TOOLS: Hello world! from binary
11-28 06:38:17.900 12479-12479/? D/TOOLS: Hello world! from static lib
看到来自于静态库的Definetion
再次修改静态库为INTERFACE,会得到这个错误
cpp\tools\tools.cpp:86:9: error: use of undeclared identifier 'LOG_TAG'
现在改动binary的PRIVATE为PUBLIC
cpp\tools\tools.cpp:86:9: error: use of undeclared identifier 'LOG_TAG'
剩下两种组合方式均为错误;
于是在官方的MailList
Hopefully the explanation that follows helps clarify what PRIVATE, PUBLIC
and INTERFACE mean and do. From my understanding of things, I think there
may have been some subtle inaccuracies in some of the discussions so far,
so hopefully the following is helpful and if I've got something wrong, then
by all means please point out the inaccuracies.
- When A links in B as *PRIVATE*, it is saying that A uses B in its
implementation, but B is not used in any part of A's public API. Any code
that makes calls into A would not need to refer directly to anything from
B. An example of this could be a networking library A which can be built to
use one of a number of different SSL libraries internally (which B
represents). A presents a unified interface for client code which does not
reference any of the internal SSL data structures or functions. Client code
would have no idea what SSL implementation (B) is being used by A, nor does
that client code need to care.
- When A links in B as *INTERFACE*, it is saying that A does not use B
in its implementation, but B is used in A's public API. Code that calls
into A may need to refer to things from B in order to make such calls. One
example of this is an interface library which simply forwards calls along
to another library but doesn't actually reference the objects on the way
through other than by a pointer or reference. Another example is where A is
defined in CMake as an interface library, meaning it has no actual
implementation itself, it is effectively just a collection of other
libraries (I'm probably over-simplifying here, but you get the picture).
- When A links in B as *PUBLIC*, it is essentially a combination of
PRIVATE and INTERFACE. It says that A uses B in its implementation and B is
also used in A's public API.
这个PRIVATE|PUBLIC|INTERFACE 是当前目标的定义域的问题:
当A使用PRIVATE去link B的PRIVATE时候使用的是自己的LOG_TAG而不是link第三方库的->因此是HELLO
当A使用PRIVATE去link B的PUBLIC时候使用的是TOOL的LOG_TAG而不是link第三方库的->因此是TOOL
这样就解释了上边LOG_TAG定义域的