XCode日常使用备忘录

2018-01-18 10:59:39 浏览数 (1)

0. Introduction

       XCode是macOS上开发app不可缺少的开发者工具,不管是开发macOS上的应用,还是iOS上的应用,都离不开XCode环境。尽管其易用性广受诟病,但由于苹果app开发的封闭性,众多开发者也不有苦不能言。近年来微软针对macOS平台发布了Visual Studio Code和Visual Studio for Mac这两款开发工具,但是其目的显然只是作为XCode的一种补充,要全盘替代XCode目前还不太现实。平时工作中由于负责开发维护Windows和Mac两个平台的应用,因此常常需要用到XCode。但由于macOS系统本来就比较逆反,用惯了Winodws陡然切换到macOS,根本无所适从。对于XCode的使用更是如此。在此记录下平时开发过程中经常用的操作,以免自己再次切换到macOS上时一脸懵逼。

1. Install name and Runpath

      install name是个什么玩意儿?简单的说,是便于加载器dyld找到程序链接的库文件。一般情况下dyld在加载程序的时候,会去一些固定的路径(如/usr/local/lib/usr/lib)下寻找需要的库文件。如果没有找到库文件,程序就会加载失败并报错。install name的出现就是为了解决这种问题,允许用户把库文件放到其他位置,通过install name告诉dylb到哪去寻找这个库文件。

      在XCode中用好install name需要设置两个地方:

(1)Build Settings->Linking,设置了Dynamic Library Install NameDynamic Library Install Name Base两项。这里用到了@rpath变量,其含义和用法在前面的博客中有细说过。@rpath其实是“runpath”的缩写,其值在第二步中设置。

     (2)Build Settings->Runpath Search Paths,设置了runpath的搜索路径。在这一项里面可以设置多个路径。这里设置的每个项都会替换@rpath,从而达到灵活设置多个位置的目的。可以在下图中看到,我们使用了@loader_path这个变量,其值实际上是可执行程序的所在位置。因此,假设可执行程序所在路径为:/Users/zhangzhongke/Library/bin/test,@loader_path/../Resources”把上面设置的@rpath替换了之后就变成了:/Users/zhangzhongke/Library/bin/test/../Resources,实际也就是:/Users/zhangzhongke/Library/Resources/。我们这里runpath只设置了一个值,实际上有需要可以设置多个值。

      通过命令otool -L可查看dylib文件的install name确实已经设置成了我们需要的值。其中:-L选项打印dylib所使用到的库,-D打印dylib文件的ID名。如果是修改其他动态库,则可使用install_name_tool命令来修改。

2. Header, Compiler and Build Locations

       Build Settings->Build Locations可以修改编译输出位置。

      Build Settings->Search Paths可设置编译时头文件和库文件的搜索路径。

      Build Settings->Apple LLVM8.0-Language C 设置C 运行时库。有的项目中需要在libstdc 和libc 之间切换,否则编译过程各种错误。

3. dSYM and App crashes

dSYM是Debug Symbols的缩写,也就是说dSYM里面存储的都是可执行程序的调试符号,对于Windows下Visual Studio生成的pdb文件。保存Release版的dSYM文件对于程序崩溃时的调试可以说极为重要。调试符号文件在调试中的作用其实非常简单,就是把那些16进制值转换为我们源代码中对应的符号变量。这样能够帮助开发者快速定位到程序崩溃的地方,极大的提高调试效率。

      那么怎么利用调试符号文件来调试程序崩溃呢?顺便记录下Windows的调试方法:

(1)Windows下利用pdb文件调试崩溃程序。首先要注意的是,要保存好Release版的pdb文件。最好发布程序时,把pdb文件也一起打包进去。

  • 调试时使用windbg,需要设置好调试符号文件和源代码文件(如果有)路径:
  • Attach to a Process适用于动态库等不能直接运行的程序,Open Executable则适用于exe可执行程序。程序起来后,直接输入g命令开始执行。在出现异常的地方运行命令:!analyze -v进行分析。windbg就能给出具体的崩溃的位置了。

(2)macOS下利用dSYM文件调试崩溃程序。首先解释下dSYM和DWARF的关系:

  •  DWARF是一种被众多编译器和调试器使用的用于支持源代码级别调试的调试文件格式。它满足了许多程序语言的需求,比如C,C 和Fortran,而且被设计成可拓展到其它语言。DWARF是平台独立的且适用于任何处理器任何操作系统。 DWARF广泛应用于Unix,Linux和其它操作系统,以及独立的环境中。
  • 为了避免进行stripping操作后调试符号的丢失,你可以使用dwarf-with-dsym选项. DWARF with dSYM 选项在标准的DWARF之外执行一个额外的步骤:创建一个单独的MyApp.app.dSYM文件,这个文件包含你的程序的所有调试符号(这个文件其实是一个包,可以通过右键->显示包内容进行查看)。事实上,DWARF with dSYM选项允许你对你进行单步调试而不管可执行程序是否被剥离了调试信息(stripped)。这是可能的,这是因为gdb将会在你的程序的目录下查找.dSYM文件。它不需要知道对象文件(object files)的名字或者路径。

利用dSYM解析crash log的主要步骤如下:

(1)在调试之前,把xxx.crash、xxx.dSYM、symbolicatecrash三个文件放到一个同一个文件夹中。这里symbolicatecrash是XCode命令行工具中的一个命令,可以把它拷贝过来,也可以建立符号链接。

代码语言:javascript复制
ln -s /Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash /usr/bin/symbolicatecrash

在我的电脑上装的是XCode8,symbolicatecrash的路径为:/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash。如果找不到,可以使用命令:

代码语言:javascript复制
find /Applications/Xcode.app/ -name symbolicatecrash -type f

(2)验证app和dSYM的UUID是否一致:

代码语言:javascript复制
dwarfdump --uuid YourApp.app/YourApp
dwarfdump --uuid YourApp.app.dSYM

(3)解析Crash Log

代码语言:javascript复制
./symbolicatecrash ./*.crash ./*.app.dSYM > symbol.crash

      生成的symbol.crash就是解析后的崩溃日志文件了,里面的符号经过了转换,阅读上变得更加友好。另外,macOS系统上的日志通常存放在如下几个地方:

代码语言:javascript复制
~/Library/Logs/DiagnosticReports/ (where ~ refers to your Home directory).
~/Library/Logs/CrashReporter/MobileDevice are the crashlogs for your iOS devices (if any).
~/Library/Logs/CrashReporter also has links to items in ~/Library/Logs/DiagnosticReports/
/var/log/system.log

  注意:Build Settings -> Build Options -> Debug Information Format中, 置成 DWARF是不会产生dSYM文件的,必须选择DWARF with dSYM File才会生成符号表文件。

4. Target, Scheme and Group

      XCode中的Target类似Visual Studio中的Project,也就是说一个target可以单独进行编译,生成可执行程序。通常在XCode中创建一个项目时,默认会创建一个同名的Target。如果需要新增一个Target,在XCode的工具栏选择:File->New->Target即可。如下图:

      创建Target的时候选择需要的项目类型即可。然后,在下图所示位置切换不同的Targets进行编译。

      注意:如果要编译不同的Targets一定要记得切换,这个功能如果Visual Studio中的“设置为启动项目”:

      如果需要设置不同Targets的项目属性,也需要进行Targets的切换:

      编辑Scheme,其实就是设置编译类型:Debug或者Release,以及一些编译动作。XCode里面有Build, Run, Test, Profile, Analysis, Archive这几个编译动作,每个动作都有Debug和Release模式。在这两种模式下设置不同的编译参数。最常用的就是Run和Archive了。

      Group在XCode里面的作用非常明确,就是用来在逻辑上对源文件进行分类管理。逻辑上的意思是,它并不会创建物理上的分组,而仅仅是视觉上、逻辑上的划分。所以有时候我们虽然在XCode中看到工程组织的井井有条,可是工程文件夹中的文件实际上是散落一片的。这个功能对于大型的项目功能划分、文件组织非常重要。下图中的New Group和New Group from Selection都是用来创建Group的,后者可以对选中的工程文件创建Group。

5. Misc 

  • xcode-select:用于选择不同版本的开发者工具
  • xcodebuild和xcrun是打包时常用的两个命令,xcodebuild负责编译,xcrun负责将app打成ipa。

6. References

  • https://gist.github.com/zchee/7833bf67013e83523181
  • http://stackoverflow.com/questions/9600615/xcode-stops-working-after-set-xcode-select-switch
  • http://log.zyxar.com/blog/2012/03/10/install-name-on-os-x/
  • https://wincent.com/wiki/@executable_path,_@load_path_and_@rpath
  • http://www.cimgf.com/2009/12/23/automatically-save-the-dsym-files/
  • http://www.cnblogs.com/max5945/p/3663966.html

0 人点赞