iOS

ios-cmake 生成framework并在Headers/保

2019-09-28  本文已影响0人  叶一帆6

前言

公司有个C/C++/ObjC的底层算法库需要在IOS上使用,做了一番调查之后决定将其编成framework的形式(至于IOS上静态库、动态库和framework的区别,网上已经有很多文章了,这里就不再累述了)。

提醒:底下的大部分链接都需要翻墙访问。

正文

ios-cmake生成framework

由于项目一直是用CMake来管理,所以找到了ios-cmake生成framework的方法,在Github上就有:用cmake生成ios framework库。我使用的是其中的第二种方法,也就是使用这里的ios.toolchain.cmake进行编译。

其中困扰了很久的问题就是如何在framework/Headers中保留原有项目的目录结构,找了很久,提出这个问题的人不少,但解决方案不合适,比如这里的:iOS框架标题不保留文件夹层次结构
一开始我采用了shell脚本手动移动文件的方法来达成需求,但这样对于一个大型项目来说显然是很low的,一旦文件目录更改,就得同时修改CMakeLists.txt和shell脚本,改的越多,出错就越容易。所以还是得找到一个可以在CMake里面实现的方法,最终被我找到了,如果急着解决,可以看这里:一个2010年的帖子。不着急的话,就看一下我在底下写的一个小例子吧。

项目结构和初步的CMakeLists.txt

如图所示,源文件和头文件按功能模块分目录,都在src底下,src/CMakeLists.txt负责编译这些文件,顶层目录有三个文件:

在这里插入图片描述

src/CMakeLists.txt

主要部分是“用cmake生成ios framework库”这里提到的,而在framework/Headers保留目录结构的关键则是:MACOSX_PACKAGE_LOCATION

src/CMakeLists.txt内容如下所示,备注应该挺清楚的了的吧。

cmake_minimum_required(VERSION 3.0)
set(CMAKE_CXX_STANDARD 11)

# 在这里所指示的目录将会成为最终framework/Headers底下的目录
set(dir1 dir1/test.cc dir1/test.h)
set(dir1_ios dir1/ios/test_ios.cc dir1/ios/test_ios.h)
set(dir2_1 dir2/subDir1/test2.cc dir2/subDir1/test2.h)
set(dir2_2 dir2/subDir2/test3.cc dir2/subDir2/test3.h)
set(dir3 dir3/test.cc dir3/test.h)

add_library(testFramework
    ${dir1}
    ${dir1_ios}
    ${dir2_1}
    ${dir2_2}
    ${dir3}
    )  

# 这里链接了第三方库:opencv.framework和几个系统库
set_target_properties(testFramework PROPERTIES
    #-F后面接着的是opencv2.framework所在目录
    LINK_FLAGS "-W1,-F${CMAKE_CURRENT_SOURCE_DIR}/3party/opencv/ios"
    )
target_link_libraries(testFramework 
        "-framework opencv2"
        "-framework Foundation" 
        "-framework CoreVideo"
        "-framework coreml"
        )

# 列出要编译的所有源文件和头文件
set(SRC_FILES
    ${dir1}
    ${dir1_ios}
    ${dir2_1}
    ${dir2_2}
    ${dir3}
    )

# 从SRC_FILES列表中找出所有头文件,并放入INCLUDE_FILES变量中
set(INCLUDE_FILES "")
foreach(file ${SRC_FILES})
    # 通过识别".h"子字符串的方式得出一个文件是否是头文件,所以.h和.hpp文件都会被找到
    string(FIND ${file} ".h" pos REVERSE)  
    if(NOT ${pos} MATCHES "-1")
        message(STATUS "header file: ${file}")
        list(APPEND INCLUDE_FILES ${file})
    endif()
endforeach(file)
set(INCLUDE_FILES ${INCLUDE_FILES} CACHE INTERNAL "List of include files" FORCE)

set_xcode_property(testFramework GCC_GENERATE_DEBUGGING_SYMBOLS YES "ALL")
set_target_properties(testFramework PROPERTIES
    FRAMEWORK TRUE
    FRAMEWORK_VERSION A
    MACOSX_FRAMEWORK_IDENTIFIER cn.yrh.test
    VERSION 1.0.0
    SOVERSION 1.0.0
    #PUBLIC_HEADER ${INCLUDE_FILES} # 使用另一种方法生成Headers/,所以PUBLIC_HEADER就不用了
    )

# 将INCLUDE_FILES变量中的所有文件按其路径名放入testFramework.framework/Headers中
foreach(hfile ${INCLUDE_FILES})
    # 截取出hfile变量中的路径
    string(FIND ${hfile} "/" pos REVERSE)  # 得出最后一个"/"的位置pos
    string(SUBSTRING ${hfile} 0 ${pos} dir)
    message(STATUS "subDir: ${dir}")
    # MACOSX_PACKAGE_LOCATION关键字可以将文件复制到特定的路径中,在IOS framework中,
    # 就是<name>.framework/
    set_property(SOURCE ${hfile} PROPERTY 
                MACOSX_PACKAGE_LOCATION Headers/${dir})
endforeach(hfile)

include_directories(
    .
    ${CMAKE_CURRENT_SOURCE_DIR}/3party/opencv/ios/opencv2.framework
    )

build.sh

#!/bin/bash
rm -r build-ios
mkdir build-ios
cd build-ios
cmake .. -G Xcode -DCMAKE_TOOLCHAIN_FILE=../ios.toolchain.cmake -DPLATFORM=OS64 -DARCHS=arm64 -DDEPLOYMENT_TARGET=12.2 -DENABLE_STRICT_TRY_COMPILE=TRUE -DENABLE_VISIBILITY=TRUE -DCMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM=UBX9CH9GDX
cmake --build . --config Debug
#cmake --build . --config Release

解释:最终编译出来的文件都在build-ios目录下,cmake的编译选项在leetal/ios-cmake中有详细介绍。
最终生成的framework应该是在Debug-iphoneos或Release-iphoneos目录下。

对了,这个也是我:


yeRuiHuan
上一篇下一篇

猜你喜欢

热点阅读