相关文章推荐
骑白马的包子  ·  TreeView,TreeNode,Tree ...·  2 年前    · 
鬼畜的钢笔  ·  python中numpy.random.ga ...·  2 年前    · 
慷慨大方的汤圆  ·  spring - Cannot load ...·  2 年前    · 

IOS项目可以很方便地和C/C++底层库混编,选择有好几种:

  • 将底层库编译成静态库/framework(这里可以用CMake来做,链接: ios-cmake 生成framework );
  • 直接将C/C++文件放入项目中,生成Target时再进行编译

我遇到的需求是,有一个底层库,里面有各种头文件和源文件,还有opencv2.framework、Eigen头文件等第三方文件,这个底层库是作为当前项目的子模块(git submodule)在管理着。
因为底层库会不断更新代码,作为开发者而言,将其编成静态库使用显然不太方便(因为每次改动一点就要重新编译一下),那么肯定就是用第二种方法更好一些。可是底层库的文件结构比较复杂,并且不是所有的源文件都需要使用时,简单地将所有文件添加到Xcode项目中显然是不行的。

这时就需要使用Xcodeproj来实现这一需求。不仅可以按照需求将所有的第三方文件、指定的源文件(按照原有的目录结构)引入Xcode项目中,并且在Xcode中的更改也会直接反映到该子模块中的相应文件,这意味着可以对更改进行版本控制。

  1. macBook都自带Ruby(版本一般是2.3.7),但是Xcodeproj不一定有。
    检查Xcodeproj:Xcodeproj --version; 下载Xcodeproj:gem install xcodeproj.

  2. Ruby2.3.7支持的最高Xcode compatible版本是6.3,需要在下图所示的地方修改,不然会报错不执行。
    修改Xcode compatible

  3. 模拟文件结构如下图所示:
    文件结构
    其中,test.rb是关键的脚本文件,submodule中有第三方文件(3party)和三个part。

  4. test.rb文件

require 'xcodeproj'
# 列出所有的源文件
part1_src = Array['part1/part1.cc', 'part1/part1.h']
part2_src = Array['part2/part2.mm', 'part2/part2.h']
part3_src = Array['part3/part3.m', 'part3/part3.h']
# 合并上面所有数组
submodule_ios_src = part1_src + part2_src + part3_src
# 此block会在此rb文件执行前被执行
# 作用是将Eigen移到项目中
BEGIN {
    current_dir = Dir.pwd;
    eigen_path = current_dir + '/submodule/src/3party/eigen3/Eigen';
    # 执行shell脚本的目录是此rb文件所在目录
    `rm -rf ../TestRb/Eigen`
    `cp -R #{eigen_path} ../TestRb/Eigen`
# 函数:从aGroup中递归去除源文件的file_reference
def removeBuildPhaseFilesRecursively(aTarget, aGroup)
    aGroup.files.each do |file|
        # remove all source file(not include header file)
        if file.real_path.to_s.end_with?('.m', '.mm','.cc', '.cpp', '.c') then
            aTarget.source_build_phase.remove_file_reference(file)
    aGroup.groups.each do |group|
        removeBuildPhaseFilesRecursively(aTarget, group)
project_path = '../TestRb.xcodeproj';  # 此路径以.rb文件所在为参照
project = Xcodeproj::Project.open(project_path);  # 打开项目
# 以下的所有xcodeproj方法路径都以TestRb.xcodeproj所在为参照
target = project.targets[0];  # 选择Target
puts "target: #{target.name}"
bva_ios_src_real_path = 'build/submodule/src/';
# 建立submodule文件夹reference
group = project.main_group.find_subpath(File.join('TestRb','submodule'), true);
group.set_source_tree('SOURCE_ROOT');
# 去除原有的submodule_ios_src reference
if !group.empty? then
    puts "remove all submodule reference to add new submodule reference!"
    removeBuildPhaseFilesRecursively(target, group);
    group.clear();
    group.remove_from_project;
# 添加新的submodule_ios_src reference
group = project.main_group.find_subpath(File.join('TestRb','submodule'), true);
group.set_source_tree('SOURCE_ROOT');
for file in submodule_ios_src
    #puts "#{file}"
    pos = file.rindex('/');  # 找到最后一个'/'的下标
    dir = file[0, pos];
    #puts "dir: #{dir}";
    final_dir = 'submodule/' + dir;
    group = project.main_group.find_subpath(File.join('TestRb', final_dir), true);
    group.set_source_tree('SOURCE_ROOT');
    file_ref = group.new_reference(submodule_ios_src_real_path + file);
    # 非头文件都要加到target的编译列表中(对应Target->Build Phases->Compile Sources)
    if (file.index('.h') == nil) then
        target.add_file_references([file_ref]);
# link opencv2.framework to project and target
project_framework_refs = project.frameworks_group.files;
# 先检测project中是否已经有两者的引用,避免重复添加
is_opencv2_exist = false;
for ref in project_framework_refs
    puts "framework name: #{ref.name}"
    if ref.name == 'opencv2.framework' then
        is_opencv2_exist = true;
if !is_opencv2_exist then
    puts "add opencv2.framwork reference"
    framework_ref = project.frameworks_group.new_file(submodule_ios_src_real_path + '3party/opencv/ios/opencv2.framework');
    if !target.frameworks_build_phases.include?(framework_ref) then
        target.frameworks_build_phases.add_file_reference(framework_ref);
    puts "opencv2.framwork reference already exist!"
# set FRAMEWORK_SEARCH_PATHS value
opencv2_framework_search_path = '$(SRCROOT)/' + submodule_ios_src_real_path + '3party/opencv/ios';
other_framework_search_path = '...'  # 这里可以添加其他的Framework地址
all_submodule_framework_sp = Array[opencv2_framework_search_path];
# set HEADER_SEARCH_PATHS value
eigen3_search_path = "$(SRCROOT)/TestRb";  # 将整个Eigen文件夹复制到项目下比较方便,因为文件不大
submodule_header_search_path = '$(SRCROOT)/' + submodule_ios_src_real_path;  # 需要添加这个才能搜索到src底下的文件
all_submodule_search_path = Array[submodule_header_search_path, eigen3_search_path];
# 设置Build Settings中的FRAMEWORK_SEARCH_PATHS和HEADER_SEARCH_PATHS
# 在保证项目原有的search_path不变的情况下,确保上面建立的两个Array中的值最终会放入两个设置中,而且不会有重复的值
target.build_configurations.each do |config|
    # config.build_settings是一个Hash,value一般是String或Array
    current_header_search_path = config.build_settings["HEADER_SEARCH_PATHS"];
    if current_header_search_path.is_a? Array then
        new_header_search_path = all_submodule_search_path + current_header_search_path;  # 合并两个Array
        new_header_search_path.uniq!;  # 移除重复元素
        #puts "new_header_search_path: #{new_header_search_path}";
        config.build_settings["HEADER_SEARCH_PATHS"] = new_header_search_path;
        # 不是Array就是String(可能是一个有效值或者空)
        all_submodule_search_path.push(current_header_search_path);  # 添加到当前Array
        all_submodule_search_path.uniq!;
        config.build_settings["HEADER_SEARCH_PATHS"] = all_submodule_search_path;
    # 和HEADER_SEARCH_PATHS类似的操作
    current_framework_search_path = config.build_settings['FRAMEWORK_SEARCH_PATHS'];
    if current_framework_search_path.is_a? Array then
        new_framework_search_path = all_submodule_framework_sp + current_framework_search_path;
        new_framework_search_path.uniq!;
        config.build_settings['FRAMEWORK_SEARCH_PATHS'] = new_framework_search_path;
        all_submodule_framework_sp.push(current_framework_search_path);
        all_submodule_framework_sp.uniq!;
        config.build_settings['FRAMEWORK_SEARCH_PATHS'] = all_submodule_framework_sp;
project.save;

ruby库xcodeproj使用心得

前言IOS项目可以很方便地和C/C++底层库混编,选择有好几种:将底层库编译成静态库/framework(这里可以用CMake来做,链接:ios-cmake 生成framework);直接将C/C++文件放入项目中,生成Target时再进行编译我遇到的需求是,有一个底层库,里面有各种头文件和源文件,还有opencv2.framework、Eigen头文件等第三方文件,这个底层库是作为当... 开发过程中经常遇到需要脚本拷贝文件,添加文件引用Xcode,新建group,添加文件到Build Phase以及增加-fno-objc-arc标识等,这些都可以通过脚本实现。 安装RubyXcodeproj 了解几个概念 Target:指定了一个用于产品(product), 并且包含了从工程中的一些文件中构建产品的命令. Group:Group 其实是 Xcode 中用来组织...
这几天在做个SDK遇到了很多问题,现在做完了想把制作Framework的过程分享出来(我这个SDK中也包含了其他的第三方很多Framework,所以踩了很多坑) 首先需要创建个Framework工程: 然后需要会有个“工程名.h”文件,有这么一句话: In this header, you should import all the public headers of your
1.对于系统头文件,如<openssl/rsa.h>,文件存放路径和Header Search Path要一起对应: 如:Path配置在$(PROJECT_DIR)/Kingjoy,则存放路径需要Finder中对应此目录,不能放在文件跟目录 2.Framework Search Path也一样,配置需要与Finder中的路径一致,而... Xcodeproj 是一个使用 Ruby 来创建和修改 Xcode 工程文件的工具. 我找到它的原因是 Cocoapods 也通过 Ruby 代码向 Xcode 工程中添加文件, 所以我在 Cocoapods 中找到了这一组件. 在最开始尝试使用这个工具的时候, 发现它
最近遇到一个问题,将含有C++文件的代码打包成framework时,打包时正常,但是不能正确接入到项目中使用,一直报如下错误 Undefined symbols for architecture arm64: , referenced from: 排查了很久,确定头文件framework的路径都没有问题后,确定是打包引入的C++文件所导致的,如果坚持要包含C++并且打包成framework,可...
首先在要添加到该项目下右击,选择“Add Files To “你要添加到的主项目A””,找到要引用的项目B的目录下的"B.xcodeproj"文件,直接确定引入即可 我第一次引入使用发现引入的只有一个“B.xcodeproj”文件,并不是一个类似于下面这种结构:B.xcodepr
Header Search Paths 顾名思义就是用来存放 Project 中头文件的搜索根源,没有被add到项目里的头文件,可以通过配置Header Search Paths 来引入头文件,这样的好处可以不让project 包含的文件太多,便于管理。      浅显一点的区别是,编码时候通过 #include 引入头文件的方式有两种 是只从 Header Search Paths 中搜
江丶小鱼: mOnImageAvailableListenerbu不是只调用一次嘛?我这里预览也是会相应一次,这个实时数据应该怎么拿?CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); builder.addTarget(mPreviewSurface); builder.addTarget(mImageReader.getSurface()); session.setRepeatingRequest(builder.build(), null, null);