简述
简单来讲,召回服务负责从内容池中, 拿取部分内容并返回,常用于搜索、推荐系统。
召回算法
通用召回
- 关键词
- 新热
- 分类
- 地域
- 多主题
协同过滤
- UserCF
- ItemCF
向量召回
- FM/FFM
模型召回
- TDM
简单来讲,召回服务负责从内容池中, 拿取部分内容并返回,常用于搜索、推荐系统。
1 | bash config_brpc.sh --headers="/path/to/deps/include/" --libs="/path/to/deps/lib/" --with-glog --with-thrift |
描述
1 | ERROR: something wrong with flag 'flagfile' in file '/home/wii/Git/cooking/c++/universal/third/build/gflags-2.2.2/src/gflags.cc'. One possibility: file '/home/wii/Git/cooking/c++/universal/third/build/gflags-2.2.2/src/gflags.cc' is being linked both statically and dynamically into this executable. |
解决
gflags静态库和共享库同时存在导致。gflags 是选择手动编译,在编译时为cmake指定-DBUILD_SHARED_LIBS=1
只编译共享库,如果是使用命令安装,可以尝试先移除/usr/local/lib/libgflag.a
和 /usr/local/lib/libgflag_nothread.a
。
1 | mkdir build && cd build |
更多参考这里。
提取Namespace
1 | execute_process( |
CMakeLists.txt 添加版本定义
1 | execute_process( |
设置版本信息
1 | int main(int argc, char *argv[]) { |
二进制程序打印版本信息
1 | ./bin/{app} --version |
基于gflags的设计哲学,不提供复杂的数据类型,可自行解析。
示例
1 |
|
说明
可在任意文件中定义flag,但只能定义一次(只能 DEFINE 一次,但是可 DECLARE 多次)。如果需要访问位于多个源文件中的glfag,那么在其他文件中使用 DECLARE。最好,在foo.cc
中使用 DEFINE 定义,在foo.h
中使用 DECLARE 声明,那么只要在代码中添加 #include <foo.h>
就可以使用该flag。
1 | // 修改 |
1 | static bool ValidatePort(const char* flagname, int32 value) { |
在全局初始化时(紧接着DEFINE_int32定义flag)注册检查方法,可以保证在运行main()
函数解析命令号之前执行校验。上面的代码,使用DEFINE_validator
宏指令调用 RegisterFlagValidator
方法,如果注册成功,返回true;如果第一个参数不是命令行标记或者该标记注册了其他校验,则返回false;返回值以<flag>_validator_registered
命名作为全局变量供访问。
1 | gflags::ParseCommandLineFlags(&argc, &argv, true); |
通常,改代码唯有main()
的开始。argc
和 argv
是传入main()
方法的准确参数,该例程可能会修改他们。最后的布尔参数用于指示是否从argc
中删除标记(flags)以及其参数(arguments),并同步修改argv
。如果为true,在该方法调用之后,argv只会保存命令行参数(commandline arguments),而不是命令行标记(glags)。如果为false,那么 ParseCommandLineFlags 不会修改 argc,但是会对argv中的参数重排序,使得所有的标记在最开始。比如,"/bin/foo" "arg1" "-q" "arg2"
,方法会重排序 argv 为 "/bin/foo" "-q" "arg1" "arg2"
,ParseCommandLineFlags 返回 argv 中第一个参数的索引,也即标记(flag)的后面的索引(在刚才的例子中,返回2,因为 argv[2] 指向第一个参数 arg1)。
注,命令行标记(commandline glags)形如 -e -q
,命令行参数(commandline arguments)形如 arg1 arg2
。
1 | foo --nobig_menu -languages="chinese,japanese,korean" ... |
当运行 ParseCommandLineFlags 时,会设置 FLAGS_big_menu = false; FLAGS_languages = "chinese,japanese,korean"
。通过在标记前面添加no
,为标记设置为 false 值。以下方式均可设置 languages 值。
1 | app_containing_foo --languages="chinese,japanese,korean" |
布尔型值稍有不同。
1 | app_containing_foo --big_menu |
尽管有很多方式灵活设置标记值,但是推荐使用统一的格式 --variable=value
,对于布尔值使用 --variable/--novariable
。
注意
--undefok
来屏蔽该异常--
标记会终止标记解析,所以 foo -f1 1 -- -f2 2
,中,f1
是标记,f2
不是-h
(和 --help
同义),同样的也不支持组合标记,如 ls -la
有时候标记位于依赖库中,如果只想在一个程序中修改默认值,其他应用不变。可在 main()
方法中赋值新值,在调用 ParseCommandLineFlags
之前。
1 | DECLARE_bool(lib_verbose); // mylib has a lib_verbose flag, default is false |
这种情况下,用户依然可以在命令行中指定标记值,但是如果不指定,则使用新的默认值。
--undefok=flagname,flagname,...
--fromenv
--fromenv=foo,bar
从环境变量中读取值,如果环境变量中未定义,则会导致致命异常
1 | export FLAGS_foo=xxx; export FLAGS_bar=yyy # sh |
--tryfromenv
--fromenv
,区别是如果环境变量中未定义标记,不会导致异常--flagfile
--flagfile=f
从文件读取参数定义,文件内容为标记定义列表,每行一个
与命令行不同的是,需要等号将标记和参数值分开(命令行参数有多种设置方式,可不加等号)
1 | 示例文件 /tmp/myflags: |
注意:flagfiles方式,一些错误会默认禁止。特别的,未识别的标记名异常默认忽略(这在命令行设置方式下,需要显式使用--undefok
指定),以及未指定值的异常(比如在flagfile中只定义 --languages
,而不指定参数)
通常的 flagfile 比示例要复杂:一系列文件名,每行一个,每个后面紧接着一系列标记,每行一个,根据需要重复多次。flagfile中的文件名可用通配符,比如 *
和 ?
,仅当当前程序的名称和flagfile文件中filenames中的一个匹配时,才会处理其挨着的标记
以 #
开头的行会被忽略
空白行及前置空白符会被忽略
可在 flagfile 中使用 --flagfile
指定其他 flagfile
标记总是以期望的方式处理,首先从检查命令行参数开始,如果遇到 flagfile ,则处理其内容,然后继续处理后续标记
1 | 示例文件 gflags_test.cmd |
移除帮助信息
可减少编译源文件时的帮助信息,及二进制文件大小,或一些安全相关的隐患。
1 |
描述
1 | ERROR: something wrong with flag 'flagfile' in file '/home/wii/Git/cooking/c++/universal/third/build/gflags-2.2.2/src/gflags.cc'. One possibility: file '/home/wii/Git/cooking/c++/universal/third/build/gflags-2.2.2/src/gflags.cc' is being linked both statically and dynamically into this executable. |
解决
在编译gflags时,使用 cmake 参数 -DBUILD_SHARED_LIBS=1
指定只编译共享库。
文学
经济学
心理学
传记
互联网
技术
效率
成长
算法
效率
编译源文件
1 | (CC) $(CPPFLAGS) $(CFLAGS) example.c -c -o example.o # -c: 编译,不执行链接操作 |
链接
1 | (CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) example.c -o example # -o: 指定输出文件名字 |
命令 | 说明 |
---|---|
CC | C 编译器 |
CXX | C++ 编译器 |
CPP | C / C++ 预编译器,通常是 “$(CC) -E” |
示例
1 | export CC=/usr/local/bin/gcc-7 |
变量 | 含义 | 示例 |
---|---|---|
CFLAGS | C 编译器选项 | |
CXXFLAGS | C++ 编译器选项 | |
CPPFLAGS | C/C++ 预处理器的命令行参数 | |
LDFLAGS | 链接参数 | |
LD_LIBRARY_PATH | 运行时动态链接库查找路径 | |
LIBRARY_PATH | 编译时链接库查找路径 | /usr/lib |
C_INCLUDE_PATH | 头文件查找路径 | |
CPLUS_INCLUDE_PATH | C++ 头文件查找路径 | |
OBJC_INCLUDE_PATH | ObjectiveC 头文件查找路径 | |
CPATH | C/C++/ObjectiveC 头文件默认查找路径,多个路径使用 : 分隔,比如 .:/root/include |
|
DYLD_LIBRARY_PATH | Mac OS 动态链接库查找路径 |
参数 | 说明 | 示例 |
---|---|---|
c | 编译 | -c |
o | 输出文件名称 | -o |
g | 添加调试信息 | -g |
l(小写L) | 链接标准库 | -lz |
L | 指定库搜索路径 | -L/user/local/lib |
I(大写i) | 指定头文件搜索路径 | -I/user/local/include |
static | 在支持动态链接的系统中,该参数覆盖-pie,并阻止链接共享库 | -static |
shared | 生成可被链接的共享对象 | -shared |
PIC / pic | 使用位置无关代码创建对象文件,创建共享库时需指定 | -fpic / -fPIC |
-llibrary
/ -l library
链接时,搜索指定库,优先使用共享库,除非指定 -static
参数官方文档。
1 | # 查找、链接库 |
CMakeLists.txt
1 | mkdir cmake-project |
Code
1 | mkdir src && vim src/main.cpp |
Config
1 | cmake_minimum_required(VERSION 3.10) |
Build
1 | mkdir build && cd build |
Run
1 | ./Tutorial |
1 | cmake_minimum_required(VERSION 2.8) |
1 | cmake_minimum_required(VERSION 2.8) |
1 | mkdir build && cd build |
1 | macro(AddLibrary MODULE) |
1 | macro(AddLibraryV2 MODULE) |
CMake是一个比make更高级的编译配置工具,它可以根据不同平台、不同的编译器,生成相应的Makefile或者vcproj项目。通过编写CMakeLists.txt,可以控制生成的Makefile,从而控制编译过程。CMake自动生成的Makefile不仅可以通过make命令构建项目生成目标文件,还支持安装(make install)、测试安装的程序是否能正确执行(make test,或者ctest)、生成当前平台的安装包(make package)、生成源码包(make package_source)、产生Dashboard显示数据并上传等高级功能,只要在CMakeLists.txt中简单配置,就可以完成很多复杂的功能,包括写测试用例。如果有嵌套目录,子目录下可以有自己的CMakeLists.txt。
CMakeLists.txt
cmake PATH
或 ccmake PATH
生成Makefile
make
命令编译,make -j4
指定编译并行度make install
安装参考 这里
1 | 3.15 + |
1 | 1 |
CMakeLists.txt 的语法比较简单,由命令、注释和空格组成。#
后面的是注释。
commond (args ...)
变量引用
变量引用用 ${VAR}
语法
set
set
命令将多变量放在一起。
1 | set (Foo a b c) |
commond(${Foo})
等价于 command(a b c)
commond("${Foo}")
等价于 command("a b c")
cmake_minimum_required
指定运行此配置文件所需的CMake的最低版本。
cmake_minimum_required (VERSION 2.8)
project
指定项目信息。
1 | project (Demo) |
add_executable
指定生成目标。
1 | add_executable(Demo demo.cpp) |
aux_source_directory
查找指定目录下的所有源文件,将结果存进指定变量名。
1 | aux_source_directory(<dir> <variable>) |
1 | cmake_minimum_required (VERSION 2.8) |
add_subdirectory
指明项目包含一个子目录,这样该目录下的CMakeLists.txt
文件和源文件也会被处理。
1 | add_subdirectory(math) |
target_link_libraries
指明可执行文件需要链接的库。
1 | target_link_libraries(Demo MathFunctions) |
add_library
将指定的源文件生成链接文件,然后添加到工程中去
1 | aux_source_directory(. DIR_LIB_SRCS) |
link_directories
指定连接器查找库的文件夹。此命令的相对路径被解释为相对于当前源目录。
格式
1 | link_directories(directory1 directory2 ...) |
示例
1 | link_directories(${PROJECT_BINARY_DIR}/third_party/googletest/) |
include_directories
将给定的目录添加到编译器用来搜索头文件的目录中。相对路径被解释为相对于当前源目录。
格式
1 | include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...]) |
示例
1 | include_directories(${PROJECT_SOURCE_DIR}/third_party/glog/) |
用于 find_package 的实现。
1 | # CACHE, 不覆盖已有值. |
1 | add_subdirectory : 建立新的 scope |
1 | bovenson@HP:~/Git/notes/C++/Code/CMake/test$ tree |
1 | Generate a Project Buildsystem |
1 | PROJECT_SOURCE_DIR 项目目录 |
1 | cmake_minimum_required(VERSION 2.8) |
1 | project("...") |
1 | if (APPLE) |
1 | add_library(name SHARED src) |
1 | SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") # 查找库文件后缀 |
1 | add_executable(MAIN src/main.cpp) |
1 | include(path/to/cmake) |
1 | MESSAGE("msg...") |
1 | set(CMAKE_C_COMPILER "gcc-5") |
1 | set(CMAKE_BUILD_TYPE=Release) # or Debug |
1 | set(CMAKE_CXX_STANDARD 11) |
1 | set(L 1 2 3) |
1 | set (L A B C) |
1 | FUNCTION(PrintTargetProperties _tgt) |
使用
1 | PrintTargetProperties(spdlog::spdlog) |
1 | execute_process( |
1 | add_definitions(-DDEBUG_MODE) # 添加字符串 |
使用
1 |
|
1 | file(GLOB_RECURSE SRCS src/**.cpp) # 递归添加 src 下所有的 cpp 文件 |
1 | if (DEFINED VAR_NAME) # NOT DEFINED VAR_NAME |
1 | string(TOUPPER ${ORIGIN_VAR} DEST_VAR) |
1 | if (${V} STREQUAL "") |
1 | # option, 只对 BOOL 类型, 默认 OFF |
1 | build director |
{library}.pc.in
1 | prefix=@CMAKE_INSTALL_PREFIX@ |
cmake config
1 | SET(PKG_CONFIG ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc) |
1 | export CMAKE_PREFIX_PATH="$CUSTOME_LIBRARY_PATH" |
1 | # 将库路径写入 CMAKE_PREFIX_PATH |
示例
1 | find_package(Snappy REQUIRED) |
1 | find_path(THRIFT_INCLUDE_DIR |
引入第三方库的几种方式。第一种,find_path 查找头文件,find_library 查找库文件,分别使用 include_directories(DEP_INCLUDE_DIR)、target_link_libraries(target library) 链接库,这种方式一般用于没有 Find*.cmake 的库。第二种,对于有 Find cmake 的库,可以使用 find_package(Library REQUIRED) 来 import 库,然后使用 target_link_libraries 来链接库。第三种,自定义 Find Cmake 文件,借助 find_package_handle_standard_args 实现。对于有 pkgconfig 的库来说,也可以用 pkg_check_modules 来导入,但是有个问题,pkgconfig 内可能有写死的 prefix,移动之后可能会出现找不到库的问题。
1
2
3
4
5
6
7
8
9
10
11
12
13
14 # snappy
find_package(Snappy REQUIRED)
target_link_libraries(brpc-static Snappy::snappy)
# thrift
find_path(THRIFT_INCLUDE_DIR NAMES thrift/Thrift.h PATH_SUFFIXES include)
find_library(thrift thrift REQUIRED CONFIG)
include_directories(${THRIFT_INCLUDE_DIR})
target_link_libraries(brpc-static thrift)
# pkg_check_modules
include(FindPkgConfig)
pkg_check_modules(Curl libcurl REQUIRED)
# Curl_INCLUDE_DIR、Curl_LIBRARIES、Curl_FOUND 会被设置
示例
1 | include(FindPkgConfig) |
简版
文档。
1 | search |
自己添加 target
1 | # 完整签名 |
1 | find_package(PackageName CONFIG) |
CONFIG
命令会尝试搜索包提供的 <PackageName>Config.cmake
或 <lowercasePackageName>-config.cmake
文件,并把包含该文件的文件夹路径赋值给 <PackageName>_DIR
,<PackageName>_CONFIG
保存配置文件的完整路径。
1 | find_package (<package> PATHS paths... NO_DEFAULT_PATH) |
1 | 不管是否找到都会设置 |
1 | include(ExternalProject) |
1 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lstdc++ -ldl") |
1 | add_library(${TGT} STATIC IMPORTED GLOBAL) |
FetchContent_Declare 通常和 FetchContent_MakeAvailable 一块使用。
FetchContent_MakeAvailable 是 cmake 3.14 引入的。
FetchContent_Declare 的参数参考 ExternalProject_Add,和 ExternalProject_Add 相比,屏蔽了下面的命令。
CONFIGURE_COMMAND
BUILD_COMMAND
INSTALL_COMMAND
TEST_COMMAND
1 | FetchContent_Declare( |
如果 CMakeLists.txt
文件不在仓库根目录下,可以用 SOURCE_SUBDIR
来指定子路径。
1 | include(FetchContent) |
1 | function(FNAME) |
方法有独立的作用域,可以访问父级作用域内的变量。在函数内定义的变量,对父级作用域不可访问。如果需要修改父级作用域变量,需要使用 PARENT_SCOPE。
1 | SET(VAR vALUEe PARENT_SCOPE) |
1 | function(ARG version url flag) |
首先了解在函数内定义的默认变量。
1 | function(ARG4) |
1 | macro(MName) |
Macro 和 function 比较相似,区别如下。
1 | cmake --preset=default # 读取 CMakePresets.json 中的 default 配置项 |
CMakePresets.json 示例。
1 | { |
1 | pwd: {project}/build |
1 | 安装 |
指定安装目录。
1 | 系统路径 |
1 | 使用 install |