iOS framework动态库的创建和使用

iOS framework动态库的创建和使用,第1张

软件:xcode12

FrameWork既可能是动态库,也可能是静态库,我们这里创建的是动态库。

选择FrameWork。默认创建的是Framework动态库

设置动态库名称

修改项目的iOS Deployment Target为10.0(与使用动态库项目保持一致,或者低于使用的项目)

MyFramework.h是默认生成的,会自动添加到暴露的header中,可以在内部import一些自己需要暴露使用的头文件。

创建文件,并添加想要暴露的头文件

(可选)设置动态库支持bitcode,如果不支持bitcode,使用动态库的项目就不能支持bitcode

动态库支持bitcode: https://www.jianshu.com/p/c5570751fdbc

第一步,DEPLOYMENT_POSTPROCESSING = YES

第二步,设置 STRIP_STYLE 为 Debugging Symbols(默认是)

第三步,Build Settings ->Compiler Flags添加 -fembed-bitcode 参数

第四步,确认Build Settings ->Enable Bitcode 为YES(默认是)

设置Edit Scheme的Run的build Configuration为Release,以便于打出来的framework是凳培release的。当然你也可以使用debug的进行调试。

simulator和真机的framework包如果需要进行合成一个调试包,需要去掉模拟器的arm64,因为xcode12合成的时候,会因为simulator和真机的包都包含arm64的而产生冲突。

选择任何simulator进行build,生成simulator的包,使用Any iOS Device进行build,生成真机的包。

生成之后在项目目录的products下的Myframework.framework进行Show in Finder,就可以看到生成的framework包。我们可以把两个包拷贝出来然后

两个包都可以单独进行调试,但是真机的包需要使用本地的证书进行重签名。

将两个包的可执行文件进行合成:

1>cd到你合成文件想要放置的文件夹下(避免当前文件夹下有和可执行文件名称相同的文件或者文件夹,有的话会报错)

2>终端执行命令:lipo -create sumulator的framework的可执行文件的目录 真机的framework的可执行文件的目录 -output 可执行文件名

lipo -create /Users/admin/Desktop/work/dylib/Release-iphonesimulator/MyFramework.framework/MyFramework /Users/admin/Desktop/告困work/dylib/Release-iphoneos/MyFramework.framework/MyFramework -output MyFramework

3>将生成的可执行文件替换Release-iphoneos中的MyFramework.framework下的可执行文件。MyFramework.framework则就是合袜粗念成的包。

4>对合成的包进行开发者证书(使用动态库项目的开发者证书)签名,签名之后就生成了可进行sumulator和真机调试的framework动态包。

签名方式:重新打开终端输入/usr/bin/security find-identity -v -p codesigning 列出电脑上可用的签名,cd到XX.framework所在的目录,然后codesign -fs "Apple Development: xxxx (XXXX)" xx.framework进行签名。

注意:打包测试或者发布的时候是直接使用没有签名过的真机的framework,xcode会自动进行签名。

项目使用动态库framework

把动态库添加到项目,然后在Build Phases的Copy Bundle Resources中添加动态库,这样动态库在打包的时候可以打包到bundle中。Link Binary Libraries如果添加了的话,动态库在程序运行的时候就会自动动态加载,可以直接使用,如果没有添加,则需要我们使用loadAndReturnError或者dlopen(私有api不能上线使用)进行加载,加载成功之后进行使用。

动态加载库方式:

1> Build Phases的Copy Bundle Resources中添加动态库,Link Binary Libraries删掉动态库。如果Link Binary Libraries需要链接的话需要在Build Settings->Links->Runpath Search Paths中添加@executable_path/

2>使用

如果重复添加动态库,则后面添加的动态库失效。

如果framework中使用到了Category那么在使用framework的工程中要设置Build Settings中的Other Link Flag为-ObjC或者-all_load

先说明下”all:“和”clean:“。这两个语句类似于:if (arg=="all") then.... 和 if (arg=="clean") then...

也就是说,如果你执行make all,all后面的语句就会被执行。

如果make clean,clean后面的语句就会被执行。

另外,all和clean后面的语句应该都是要缩进的。

EXEC = hello // 生成的可执行文件名为hello

OBJS = hello.o // 编译产生的仔橘中间文件名为hello.o

CROSS= iwmmxt_le- //设置iwmmxt_Ie-为交叉编空和译环境

CC = $(CROSS)gcc // 编译器是gcc

STRIP= $(CROSS)strip // 设置优化器斗戚盯(用来删除debug信息)

CFLAGS = -Wall -g -O2 // 设置编译选项

all: clean $(EXEC) // 如果是make all,先掉用下clean后面的指令,再执行自己下面的指令

$(EXEC):$(OBJS) // 创建依赖关系。这里表示hello依赖于hello.o。也就是说,先产生hello.o再产生hello

$(CC) $(CFLAGS) -o $@ $(OBJS) // 编译

$(STRIP) $@ // 删除debug信息

clean: // make clean就会来这里

-rm -f $(EXEC) *.o // 删除产生的中间文件

C++#ifndef与#ifdef的区别是什么? #ifndef 表示如果没有定义宏 则条件成立,如:

#ifndef EXTERNchar globle_str[100]#elseextern char globle_str[]#endif如果没有定义宏 EXTERN 则定义一个变量char globle_str[100] 否则,引用声明该变量extern char globle_str[]把这个信息写入一个头文件,如:globe.h,可在多个源代码中引用这个头文件。源文件中,如果加了#define EXTERN,则在编译时,就会调用extern char globle_str[]进行编译,如果没有加,就会调用char globle_str[100]

#ifdef 表示如果定义了宏 则条件成立,如,上面的例子,可改写成:

#ifdef EXTERNextern char globle_str[]#elsechar globle_str[100]#endif如果定义了宏 EXTERN 则引用声明变量extern char globle_str[]否则,定义一个变量char globle_str[100]

相关代码引用:

globe.h: 如上面内容

out.c:

#define EXTERN定义宏EXTERN后引用头文件globe.h#include "globe.h" #include <stdio.h>void output(){puts(globe_str)}

main.c:

这里没有定义EXTERN#include "globe.h" void output()int main(){sprintf( globe_str, "hello world") output() return 0}

C++中if、#if与#ifdef、#ifndef彼此的区别

以#开头的都是预编译指令,就是在正式编译之前,编译器做一些预处理的工作

#if 条件语颤粗句

程序段1 如果条件语句成立,那么就编译程改洞笑序段1

#endif

程序段2如果条件不语句成立,那么就编译程序段2

#ifndef x先测试x是否被宏定义过

#define 程序段1 如果x没有被宏定义过,那么就编译程序段1

#endif

程序段2 如果x已经定义过了则编译程序段2的语句,“忽视”程序段1。

#ifdef x 先测试x是否被宏定义过

程序段1 如果x被宏定义过,那么就编译程序段1

#endif

程序段2 如果x没有被定义过则编译程序段2的语句,“忽视”程序段1。

if就是判断语句,不是预编译指令

makefile中ifeq,ifneq,ifdef和ifndef的区别与用法

1,Makefile中的ifeq:ifeq($(ABC), XXX) CFLAGS += -DABC endif 注意: 逗号和xxx之间必须有一个空格 更需要注意的是: ifeq中的XXX后面不能带空格,如果XXX后面带了一个空格,那空格和XXX会被认为是一个整体 export ABC = XXX[ ][ ] 这里用【】表示一核含个空格 那么 ifeq($(ABC), XXX ...

2,Makefile中四种变量赋值的区别:Ask: What is the difference beeen : VARIABLE = value VARIABLE ?= value VARIABLE := value VARIABLE += value I have read the section in GNU Make's manual, but it still doesn't ...

3,,Makefile 中:= ?= += =的区别:在Makefile中我们经常看到 = := ?= +=这几个赋值运算符,那么他们有什么区别呢?我们来做个简单的实验 新建一个Makefile,内容为:ifdef DEFINE_VREVRE = “Hello Wo ...

,4,zz makefile中=和:=的区别:在Makefile中我们经常看到 = := ?= +=这几个赋值运算符,那么他们有什么区别呢?我们来做个简单的实验 新建一个Makefile,内容为:ifdef DEFINE_VREVRE = “Hello W ...

,5,嵌入式 Makefile中:=与=与+=与=的区别$@,$^,$<区别:在Makefile中我们经常看到 = := ?= +=这几个赋值运算符,那么他们有什么区别呢?我们来做个简单的实验 新建一个Makefile,内容为: ifdef DEFINE_VRE VRE = "HelloWorld!" else endif ifeq ($(OPT),define) VRE ?="Hello 。

makefile中ifeq,ifneq,ifdef和ifndef的区别与用法

使用条件判断,可以让make根据运行时的不同情况选择不同的执行分支。条件表达式可以是比较变量的值,或是比较变量和常量的值。

一、示例

下面的例子,判断$(CC)变量是否“g”,如果是的话,则使用GNU函数编译目标。

libs_for_g = -lgnu

normal_libs =

foo: $(objects)

ifeq ($(CC),g)

$(CC) -o foo $(objects) $(libs_for_g)

else

$(CC) -o foo $(objects) $(normal_libs)

endif

可见,在上面示例的这个规则中,目标“foo”可以根据变量“$(CC)”值来选取不同的函数库来编译程序。

我们可以从上面的示例中看到三个关键字:ifeq、else和endif。ifeq的意思表示条件语句的开始,并指定一个条件表达式,表达式包含两个参数,以逗号分隔,表达式以圆括号括起。else表示条件表达式为假的情况。endif表示一个条件语句的结束,任何一个条件表达式都应该以endif结束。

当我们的变量$(CC)值是“g”时,目标foo的规则是:

foo: $(objects)

$(CC) -o foo $(objects) $(libs_for_g)

而当我们的变量$(CC)值不是“g”时(比如“”),目标foo的规则是:

foo: $(objects)

$(CC) -o foo $(objects) $(normal_libs)

当然,我们还可以把上面的那个例子写得更简洁一些:

libs_for_g = -lgnu

normal_libs =

ifeq ($(CC),g)

libs=$(libs_for_g)

else

libs=$(normal_libs)

endif

foo: $(objects)

$(CC) -o foo $(objects) $(libs)

二、语法

条件表达式的语法为:

<conditional-directive>

<text-if-true>

endif

以及:

<conditional-directive>

<text-if-true>

else

<text-if-false>

endif

其中<conditional-directive>表示条件关键字,如“ifeq”。这个关键字有四个。

第一个是我们前面所见过的“ifeq”

ifeq (<arg1>, <arg2>)

ifeq '<arg1>' '<arg2>'

ifeq "<arg1>" "<arg2>"

ifeq "<arg1>" '<arg2>'

ifeq '<arg1>' "<arg2>"

比较参数“arg1”和“arg2”的值是否相同。当然,参数中我们还可以使用make的函数。如:

ifeq ($(strip $(foo)),)

<text-if-empty>

endif

这个示例中使用了“strip”函数,如果这个函数的返回值是空(Empty),那么<text-if-empty>就生效。

第二个条件关键字是“ifneq”。语法是:

ifneq (<arg1>, <arg2>)

ifneq '<arg1>' '<arg2>'

ifneq "<arg1>" "<arg2>"

ifneq "<arg1>" '<arg2>'

ifneq '<arg1>' "<arg2>"

其比较参数“arg1”和“arg2”的值是否相同,如果不同,则为真。和“ifeq”类似。

第三个条件关键字是“ifdef”。语法是:

ifdef <variable-name>

如果变量<variable-name>的值非空,那到表达式为真。否则,表达式为假。当然,<variable-name>同样可以是一个函数的返回值。注意,ifdef只是测试一个变量是否有值,其并不会把变量扩展到当前位置。还是来看两个例子:

示例一:

bar =

foo = $(bar)

ifdef foo

frobozz = yes

else

frobozz = no

endif

示例二:

foo =

ifdef foo

frobozz = yes

else

frobozz = no

endif

第一个例子中,“$(frobozz)”值是“yes”,第二个则是“no”。

第四个条件关键字是“ifndef”。其语法是:

ifndef <variable-name>

这个就不多说了,和“ifdef”是相反的意思。

在<conditional-directive>这一行上,多余的空格是被允许的,但是不能以[Tab]键做为开始(不然就被认为是命令)。而注释符“#”同样也是安全的。“else”和“endif”也一样,只要不是以[Tab]键开始就行了。

特别注意的是,make是在读取Makefile时就计算条件表达式的值,并根据条件表达式的值来选择语句,所以,最好不要把自动化变量(如“$@”等)放入条件表达式中,因为自动化变量是在运行时才有的。

而且,为了避免混乱,make不允许把整个条件语句分成两部分放在不同的文件中。

C++中*与*&的区别是什么

*是取值运算符,对地址使用可以获得地址中储存的数值;&是地址运算符,对变量使用可以获得该变量的地址。恩,简单说就是这样,有疑问请继续追问。。。

C++中,break与return的区别是什么?

最本质的区别:

break是用来跳出循环的,例如for,while,do-while都可以跳出,但不跳出函数

return是使整个函数返回的,后面的不管是循环里面还是循环外面的都不执行

再说一下,break语句通常用在循环语句和开关语句中,当break语句用于do-while、for、while循环语句中时,可使程序终止循环而执行循环后面的语句, 通常break语句总是与if语句联在一起,即满足条件时便跳出循环

return语句是将函数的值返回主调函数。

还有一个continue语句的作用是跳过循环本中剩余的语句而强行执行下一次循环。continue语句只用在for、while、do-while等循环体中,常与if条件语句一起使用,用来加速循环

c++==========getparent与afxgetmainwnd的区别是什么。

GetParent获得是父窗口指针(一般是CFrameWnd*主窗口指针)。但是GetParent获得上级父窗口指针,他不一定是主窗口。 GetParent()是获得父窗体的cwnd 而对话框的父窗体不一定mainWnd

AfxGetMainWnd获取自身窗口句柄。

如果你的应用程序是一个OLE服务器,应该调用这个函数以获得应用程序的活动主窗口指针,而不是直接引用应用程序对象的m_pMainWnd成员。

如果你的应用程序不是OLE服务器,那么调用这个函数与直接引用应用程序对象的m_pMainWnd成员是等价的。

注意:如果AfxGetMainWnd被应用程序主线程调用,它返回应用程序的主窗口。如果该函数被应用程序的次线程调用,该函数返回与引起该调用线程连接的主窗口。

赛扬C与D的区别是什么?

赛扬没有C只有赛扬4跟赛扬D之分,赛扬4是100MHz外频、FSB400MHz。赛扬D是133MHz外频、FSB533MHz。赛扬D420之后的所有赛扬就是core核心的了,跟以前的半点关系都没了。

C++中::Vac与Vac的区别是什么?

Vac前面的两个冒号(::)是全局作用域解析符, 用来表示内部函数里的全局变量

举个例子来说吧

==========================

#include<iostream>

using namespace std

int Vac = 0全局的Vac

int main(int argc, char *argv[])

{

int Vac = 1局部的Vac

cout <<::Vac <<" \n" <<Vac <<"\n"

return 0

}

===========

::Vac 表示的是那个全局的Vac

Vac表示的是局部的那个


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/12260450.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-24
下一篇 2023-05-24

发表评论

登录后才能评论

评论列表(0条)

保存