IOS项目可以很方便地和C/C++底层库混编,选择有好几种:
我遇到的需求是,有一个底层库,里面有各种头文件和源文件,还有opencv2.framework、Eigen头文件等第三方文件,这个底层库是作为当前项目的子模块(git submodule)在管理着。
因为底层库会不断更新代码,作为开发者而言,将其编成静态库使用显然不太方便(因为每次改动一点就要重新编译一下),那么肯定就是用第二种方法更好一些。可是底层库的文件结构比较复杂,并且不是所有的源文件都需要使用时,简单地将所有文件添加到Xcode项目中显然是不行的。
这时就需要使用Xcodeproj来实现这一需求。不仅可以按照需求将所有的第三方文件、指定的源文件(按照原有的目录结构)引入Xcode项目中,并且在Xcode中的更改也会直接反映到该子模块中的相应文件,这意味着可以对更改进行版本控制。
-
macBook都自带Ruby(版本一般是2.3.7),但是Xcodeproj不一定有。
检查Xcodeproj:Xcodeproj --version; 下载Xcodeproj:gem install xcodeproj.
-
Ruby2.3.7支持的最高Xcode compatible版本是6.3,需要在下图所示的地方修改,不然会报错不执行。
-
模拟文件结构如下图所示:
其中,test.rb是关键的脚本文件,submodule中有第三方文件(3party)和三个part。
-
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标识等,这些都可以通过脚本实现。
安装Ruby库Xcodeproj
了解几个概念
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 中搜
江丶小鱼: