So Tired !_! 逆水行舟, 不进则退!

17Aug/20

pyenv 让 python 版本完美切换

Posted by Nick Xu

前言

我觉得如果使用 python 开发的话,还是在 unix/linux 的环境下吧,shell 工具的效率比 windows 高得多,尽管 windows 下也有 cmder 这种神器,而且现在 windows store 也很好的开发出了 linux 子系统,但是瑕疵非常多,unix/linux 才是完美的环境。本文用到的是 archlinux ,另外 debian/ubuntu、centos 也完全适用。mac 用户也可以参考,不过 homebrew 也提供了非常方便的安装方法,但是建议使用文本做法。

背景

python 版本比较多,2 和 3 相差非常大,很多项目需要跑在同一台服务器上,我们可以选择直接运行,也可以选择使用 docker。如果用 docker 那就不需要隔离环境了,如果要直接运行在服务器上,那就必须有隔离环境。比如有的项目使用 python 3.5,有的项目使用 python 3.7,此时我们可以借助 pyenv 帮助我们完美的隔离环境,让多个版本的 python 没有任何冲突,完美共存。

任务

使用 pyenv 和 pyenv-virtualenv ,在 linux 下完美隔离 python 各个版本

第 1 章:使用环境

请注意,接下来所有的操作都在 archlinux 下进行,本文不涉及 windows

清单

  1. git
  2. zsh 或者 bash
  3. pyenv
  4. pyenv-virtualenv

1、安装 git

在各大 linux 的发行版下安装 git 都非常简单,此处只展示部分示例

archlinux

sudo pacman -S git

debian/ubuntu

sudo apt-get install git

centos

sudo yum install git

2、开启终端

本文使用 zsh

3、安装 pyenv

说明:本文的所有安装都严格遵守官方文档,与官方文档完全保持一致。

git 地址:https://github.com/pyenv/pyenv

在你的终端中执行如下命令,安全无毒,请放心食用:

首先把项目克隆下来,放在家目录下的隐藏文件夹中:.pyenv

git clone https://github.com/pyenv/pyenv.git ~/.pyenv

然后配置环境变量

如果你使用 bash,就依次执行如下命令:

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc

echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc

echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.bashrc

如果你使用 zsh,就依次执行如下命令:

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc

echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc

echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.zshrc

echo 命令的含义是:将引号中内容写入某文件中
请注意,以上的三条 echo 命令的最后一条长长的命令,请你保证它引号中的内容处于 ~/.bashrc 或者 ~/.zshrc 的最底部。
因为在 pyenv 初始化期间会操作 path 环境变量,导致不可预测的行为。
查看文件的底部内容,可以使用 tail 命令,用法:tail ~/.bashrc 或者 tail ~/.zshrc,编辑文件可以使用 vim 或者 vscode

最后,在使用 pyenv 之前,重新初始化 shell 环境,执行如下命令

exec $SHELL

不执行该命令也是完全可以的,你可以关闭当前的终端窗口,重新启动一个就可以了。

此时,你已经完成了 pyenv 的安装了,你使用可以它的全部命令了,但是我建议你先别急着用,一口气装完 pyenv 的一个插件,那就是 pyenv-virtualenv

4、安装 pyenv-virtualenv

git 地址:https://github.com/pyenv/pyenv-virtualenv

把插件克隆在刚才已经安装完毕的 pyenv 的 plugins 文件夹中

git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv

然后配置环境变量

如果你使用 bash,就执行如下命令:

echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc

如果你使用 zsh,就执行如下命令:

echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.zshrc

最后,在使用 pyenv 之前,重新初始化 shell 环境,执行如下命令

exec $SHELL

不执行该命令也是完全可以的,你可以关闭当前的终端窗口,重新启动一个就可以了。

到此,我们的所有重要安装已经全部完成了,可以开始体验了。

第 2 章:使用 pyenv

此处仅仅展示 pyenv 和 virtualenv 的日常用法

检查安装是否正确

检查 pyenv 的版本

pyenv version

查看 pyenv 已经托管了哪些 python 版本

pyenv versions

如果你看到了正常的版本信息,就说明可以了,如果看到了类似于 command not found 之类的,就说明安装失败了。

安装 3.6.6 版本的 python

pyenv install 3.6.6

这里有个问题,某些情况下会安装失败,报错就告诉你 Build failed

这个时候,pyenv 已经在它的 github wiki 里面为我们准备了一篇错误应对方案,原文地址 https://github.com/pyenv/pyenv/wiki

大意如下,只需要执行对应的命令即可:

archlinux 用户

sudo pacman -S base-devel openssl zlib

mac 用户

brew install openssl readline sqlite3 xz zlib

Ubuntu/Debian/Mint 用户

sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev

CentOS/Fedora <= 21 用户,请你保证已经安装了 xz 工具

sudo yum install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel

Fedora >= 22 用户,请你保证已经安装了 xz 工具

sudo dnf install -y gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel

openSUSE 用户

zypper install gcc automake openssl-devel ncurses-devel readline-devel zlib-devel tk-devel

Solus 用户

sudo eopkg it -c system.devel

sudo eopkg install git gcc make zlib-devel bzip2-devel readline-devel sqlite3-devel openssl-devel tk-devel

Linuxbrew 用户

brew install bzip2 openssl readline sqlite xz

安装完这些补充的工具之后,再次执行:

pyenv install 3.6.6

就可以成功了,你可以不断的使用

pyenv versions

来查看被 pyenv 托管的 python 版本

而且你想装什么版本就装什么版本,想装几个装几个,都是完美共存,完美隔离,你可以在终端里输入

pyenv install

然后按下 tab 键,就可以看到所有可选的安装版本了

使用刚才安装的 python 3.6.6

首先我们需要明确一个概念,pyenv 和 pyenv-virtualenv 他们是如何协作的,你可以这么认为:

pyenv 托管 python 版本,virtualenv 使用 python 版本

好了,之前已经装好了版本,那么现在就来使用吧

第 1 步:创建虚拟环境

首先需要创建一个虚拟环境,执行命令:

pyenv virtualenv 3.6.6 my-env

它的格式就是这样固定的,最后一个是你自己想要的环境的名字,可以随便取。稍等片刻,你将会看到:

Looking in links: /tmp/tmp0eywgc7v
Requirement already satisfied: setuptools in /home/joit/.pyenv/versions/3.6.6/envs/my-env/lib/python3.6/site-packages (39.0.1)
Requirement already satisfied: pip in /home/joit/.pyenv/versions/3.6.6/envs/my-env/lib/python3.6/site-packages (10.0.1)

类似于这样的回显信息,说明环境已经创建成功了,它还告诉了你,该虚拟环境的绝对路径,如果你进去看了,你就会发现,所谓的虚拟环境,就是把 python 装在 pyenv 的安装目录的某个文件夹中,以供它自己调用。

第 2 步:激活虚拟环境

在任意目录下,执行命令:

pyenv activate my-env

你会发现,在你的终端里面,多了一个类似于 (my-env) 这样的一个东西,这时候你如果执行:

python --version

那就是 python 3.6.6 了

如果你执行:

pip --version

它会告诉你 pip 包安装的绝对路径,也是 pyenv 安装目录下的某个文件夹

如果你关掉了终端,那么下次启动你又得重新激活一次了,你可以使用如下命令:

首先 cd 到某一个目录,比如 ~/test

cd ~/test

然后在该目录下执行:

pyenv local my-env

你会发现已经被激活了,那么 local 命令和刚才有啥不同呢。如果你执行:

ls -al

你就会发现,在 ~/test 目录下,有个隐藏文件 .python-version,你可以看到这个文件里面,只写了一句话 my-env

这样你只要进入 ~/test 目录,就会自动激活虚拟环境

在虚拟环境下,你如果直接执行

python

就会进入到 python 的交互环境

如果你写了一个文件,名字叫做 app.py ,里面的内容只有一句代码:print(1)

然后执行:

python app.py

这时候,系统就会调用虚拟环境中的 python 解释器来执行这些代码了

第 3 章:更新 pyenv

由于我们是 git 克隆的,所以更新非常简单

cd ~/.pyenv 或者 cd $(pyenv root)
git pull

第 4 章:卸载 pyenv

由于 pyenv 把一切都放在 ~/.pyenv 下了,所以卸载很方便,两个步骤就行了

首先你需要删除环境变量

然后你需要执行:

rm -rf ~/.pyenv 或者 rm -rf $(pyenv root)

作者:JoiT
链接:https://www.jianshu.com/p/3e93311fe6cb
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Tagged as: , Comments Off
24Mar/20

homebrew安装和解决brew安装速度慢的问题

Posted by Nick Xu

homebrew安装

ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”

解决brew安装速度慢的问题(替换homebrew镜像源)

1.替换brew.git:

cd $(brew --repo)
git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git

2.替换homebrew-core.git:

cd $(brew --repo)/Library/Taps/homebrew/homebrew-core
git remote set-url origin https://mirrors.aliyun.com/homebrew/homebrew-core.git

3.终端输入命令:

echo $SHELL 看输出结果是/bin/zsh还是/bin/bash

  • /bin/zsh替换homebrew-bottles:
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.zshrc
source ~/.zshrc
  • /bin/bash替换homebrew-bottles:
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.bash_profile
source ~/.bash_profile

4.恢复homebrew国内镜像源配置

  • 重置brew.git
cd $(brew --repo)
git remote set-url origin https://github.com/Homebrew/brew.git
  • 重置homebrew-core.git
cd $(brew --repo)/Library/Taps/homebrew/homebrew-core
git remote set-url origin https://github.com/Homebrew/homebrew-core.git
  • 重置homebrew-bottles
将刚添加到~/.bash_profile文件的语句注释掉即可

解决brew安装包一直卡在Updating Homebrew

运行命令brew install node,结果界面一直卡在Updating Homebrew上,有两种解决办法

方法一:关闭brew每次执行命令时的自动更新(推荐)

vim ~/.bash_profile
# 新增一行
export HOMEBREW_NO_AUTO_UPDATE=true

方法二(懒人方法):

出现Updating Homebrew的时候ctrl+c一下就行
Tagged as: Comments Off
14Feb/20

Mac 环境将 Socks 代理转 Http 代理

Posted by Nick Xu

安装 polipo

sudo port install polipo

快速使用

$ polipo socksParentProxy=localhost:1080

配置文件方式启用

 

# vi ~/.poliporc

socksParentProxy =127.0.0.1:1080″
socksProxyType = socks5
proxyAddress = "::0"        # both IPv4 and IPv6
# or IPv4 only
# proxyAddress = "0.0.0.0"
proxyPort = 8123

运行

$ polipo -c ~/.poliporc

测试

$ curl --proxy http://127.0.0.1:8123 https://www.google.com

配置开机自启动

参考链接:mac环境下开机自启动Shell脚本

参考链接

hg使用代理,向.hgrc的末尾添加以下内容:

   [hostfingerprints]
   vim.googlecode.com=c2:8a:1e:9c:a8:00:be:02:4c:2a:53:60:2b:09:50:d8:ee:5c:bc:68        
   [http_proxy]
   host=127.0.0.1:8087
   [web]
   cacerts = /etc/ssl/certs/ca-certificates.crt
Filed under: Mac OS Comments Off
25Aug/19

‘caching_sha2_password’ cannot be loaded

Posted by Nick Xu

django访问mysql数据库报错:

django.db.utils.OperationalError: (2059, "Authentication plugin 'caching_sha2_password' cannot be loaded: dlopen(/usr/local/Cellar/mysql-connector-c/6.1.11/lib/plugin/caching_sha2_password.so, 2): image not found")

mysql8.0用户密码加密方式为caching_sha2_password,django暂不支持,需要修改下mysql的加密方式:

登录mysql:

mysql -u root -p

查看当前加密方式:

use mysql;
select user,plugin from user where user='root';

修改加密方式:

alter user 'root'@'localhost' identified with mysql_native_password by 'password';

生效:

flush privileges;

作者:倪大头
链接:https://www.jianshu.com/p/939eb5157e83
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Filed under: Mac OS, 数据库 Comments Off
21Aug/19

mac解决安装mysql-python错误my_config.h

Posted by Nick Xu

brew install mysql
brew unlink mysql
brew install mysql-connector-c
sed -i -e 's/libs="$libs -l "/libs="$libs -lmysqlclient -lssl -lcrypto"/g' /usr/local/bin/mysql_config
pip install MySQL-python
brew unlink mysql-connector-c
brew link --overwrite mysql

出现下列错误:

ld: library not found for -lssl

解决:

sudo env LDFLAGS="-I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib" pip install MySQL-python

Filed under: Mac OS, Python Comments Off
19Aug/19

macOS Sierra 合上盖子不休眠的问题及解决办法

Posted by Nick Xu

一.问题(15年款的mbp)

本人上个月买的macbook pro,刚开始每天晚上睡觉都是直接合上盖子(开着一堆程序)系统会自动休眠,但是自从前几天升级了新系统Sierra之后就发现合上盖子竟然没有休眠(第二天早上起来发现掉了50%多的电,而且温度堪比暖宝宝),而且有个同事更新Sierra后也产生了和我一样的问题,经过上网查找及调试终于发现问题所在。

系统信息.png

二.解决

1.快速方法

如果是跟我一样在没更新系统之前休眠没有任何问题但是更新之后合上盖子无法休眠,请打开--系统偏好设置->节能->电池,会看到这一栏

节能-电池.png

如果你的电脑这里显示的是2分钟,那么打开terminal终端

终端.png

然后输入pmset -g custom 检查一下电源参数

电源相关参数

看到第二个红框(电池电源参数),然后往下找到displaysleep,sleep,和disksleep参数(找不到可以参考图片里面的红线),这三个参数的意思,我引用网络上的解答

displaysleep
Mac闲置多长时间后进入显示器睡眠,单位是分钟,这个时间不能长于sleep下设置的时间
sleep
Mac闲置多长时间后进入睡眠,这个系统偏好设置里也有,单位是分钟
disksleep
Mac闲置多长时间后关闭硬盘。这个系统偏好里也有,只不过换了一个字眼—如果可能,使硬盘进入睡眠—勾上这个的话系统就会自动根据sleep的时间设一个合适的时间。单位是秒,这个时间不能长于sleep下设置的时间

  • 时间的长度比较:sleep>=displaysleep>=disksleep
    从图中看出disksleep单位是秒,一般都是最短的,而sleep和displaysleep是单位是分,系统要求是sleep的时间要大于等于displaysleep的时间,而我图里sleep(1)小于display(2),它们之间的时间冲突了导致mac在电池状态下没有正常进入休眠,所以你需要回到--系统偏好设置->节能->电池,把时间改成5分钟(反正要大于2)就可以了,改完后这时在terminal输入pmset -g custom 对比这3个参数

    修改之后.png

只要符合sleep(min)>=displaysleep(min)>=disksleep就可以了,这样mac就可以正常休眠了。
ps:这个诡异的系统设置是15年款的macbook升级到sierra后有的,因为我找了很多同事的对比,他们captian系统的电源参数都是正常符合上述的式子的,可以正常休眠,然后15年款之前的升级到sierra参数也符合,就我和另外几个15年款的mac升级sierra后出现无法休眠问题。

2.其他导致无法休眠的原因及解决办法

  • 如果不是上述原因的话,那么就是你可能下载了某些软件会在mac合上盖子还会唤醒mac从而阻止休眠,这时候打开活动监视器然后点能耗查看,把防止睡眠中如果有程序是“是”就改成“否”。
    活动监视器
  • 重置SMC
  • 如果还不行,在terminal终端输入pmset -g assertions 可以查看日志,查出是什么程序唤醒,然后关闭,这里网上有许多教程:
    传送门1
    传送门2
    苹果官方文档

 

一、关闭wifi唤醒选项

在系统偏好设置中,找到节能,将“唤醒以提供Wi-Fi网络访问关掉,合盖后耗电厉害多半是这个功能的锅,不过下资料慎重选择。

2.搜狗输入法

Mac自带的输入法不如搜狗输入法好用,但是安装了之后,在活动监视器里查看,主程序一直在写入,一天可写入高达几十G,同时严重影响能耗,这个问题部分用户是没有这个问题的,但是如果后台写入频繁,可以在Mac防火墙里直接毙掉它的网络权限。

3.修改电脑休眠模式 第一步:打开终端

第二步:输入pmset -g然后敲击回车

如果提示输入 password,直接输入你的开机密码,密码是不会显示出来的,直接输就行,输完敲回车即可

查看 hibernatemode 这一行,如果 hibernatemode 后面的数字是 0 ,那这种休眠模式下,掉电程度就是非常严重,如果 hibernatemode 后面的数字是 3 (大部分人的电脑应该是这个休眠模式),这种模式的掉电掉电程度就是一般严重,如果 hibernatemode 后面的数字是 25 ,那掉电就会更少一些(只会掉一点点)

如果你常用电脑,那么直接将休眠模式改为25即可,只掉一点电。

在终端里输入命令sudo pmset -a hibernatemode 25,然后回车;如果你想达到和关机一样的效果,再进行一步:在终端输入sudo pmset -b tcpkeepalive 0,此模式下合盖即断网,下载文件慎用。

注意:修改以上两种模式后,电脑开盖后屏幕启动速度可能会变慢一些(开盖后 3 至 5 秒屏幕才会点亮),如果介意这个,可以选择不更改。

4.后台程序阻止休眠

如果在终端命令运行之后sleep后显示休眠被程序阻止,那么一定要注意把这些后台程序咔嚓掉。

另外还有一行Standby,终端输入sudo pmset -b standby 1,回车。合上屏幕之后,在4200分钟之内如果被唤醒,则从内存直接调用数据,如果4200分钟后依然未请求唤醒,系统则会移送所有内存数据到硬盘

5.Adobe creative cloud 顽固程序

不知道在 Mac上用ps、lr、pr等产品时大家发现没有,后台一直有一些顽固的自启程序,比如core sync,这是一些无用的自启程序,是创意云的组件,占用系统资源,其实完全可以删掉。

第一步:按以下路径找到Adobe相关文件直接删掉

~/Library/LaunchAgents

/Library/LaunchAgents

/Library/LaunchDaemons

/System/Library/LaunchAgents

/System/Library/LaunchDaemons

(这里小编已经全部咔嚓掉了,就不重新安装截图了)

第二步:进入系统偏好设置,在“扩展”中关闭Core Sync和Core Sync Helper 第三步:找到根目录,将组件删除

前往/Applications/Utilities/Adobe Creative Cloud,删除CCLibrary、CCXProcess以及CoreSync文件夹

强制退出CCLibrary.app、CCXProcess.app以及CoreSync.app进程之后再删除。

如果删除了之后还存在,借助第三方clean my mac,继续将这三个卸载。

Filed under: Mac OS Comments Off
15Aug/19

pycurl libcurl link-time ssl backend (openssl) is different from compile-time ssl backend (none/other)

Posted by Nick Xu

export PYCURL_SSL_LIBRARY=openssl

pip install pycurl --compile --no-cache-dir --global-option=build_ext --global-option="-L/usr/local/opt/openssl/lib" --global-option="-I/usr/local/opt/openssl/include"

Tagged as: Comments Off
7Dec/18

(苹果Mac OSX系统)绿联USB无法连接网络解决方案

Posted by Nick Xu

检测驱动是否装载:

sudo kextload /Library/Extensions/AX88772.kext
1
note:如果已装载成功,则执行成功,否则显示错误提示。

操作如下:
step1:关机重启立马按住command+R,等待进入language界面。
step2:按需求选择后,在工具栏打开终端。
step3:输入csrutil status查看当前状态,状态为enabled。
step4:输入csrutil disable,关闭System Integrity Protection。
step5:重启电脑。
再次重新装载,如若查看还未装载成功,请下载最新驱动AX88179。
---------------------
作者:shannon-Li
来源:CSDN
原文:https://blog.csdn.net/weixin_42555131/article/details/81843315
版权声明:本文为博主原创文章,转载请附上博文链接!

Filed under: Mac OS Comments Off
23Oct/18

关于 “does not contain bitcode.”的错误解决办法

Posted by Nick Xu

Xcode7运行项目时出现了如下的错误:

does not contain bitcode. You must rebuild it with bitcode enabled
(Xcode setting ENABLE_BITCODE), obtain an updated library from the
vendor, or disable bitcode for this target. for architecture armv7

关于什么bitcode的错误,那bitcode是个什么鬼呢?

什么是 bitcode ?

通俗解释:在线版安卓ART模式。

Apple 官方文档– App Distribution Guide – App Thinning (iOS, watchOS) 是这样定义的:

Bitcode is an intermediate representation of a compiled program. Apps you upload to iTunes Connect that contain bitcode will be compiled and linked on the App Store. Including bitcode will allow Apple to re-optimize your app binary in the future without the need to submit a new version of your app to the store.

翻译过来就是:

bitcode 是被编译程序的一种中间形式的代码。包含 bitcode 配置的程序将会在 App Store 上被编译和链接。 bitcode 允许苹果在后期重新优化我们程序的二进制文件,而不需要我们重新提交一个新的版本到 App Store 上。

在 Xcode简介— What’s New in Xcode-New Features in Xcode 7 中这样描述:

Bitcode. When you archive for submission to the App Store, Xcode will compile your app into an intermediate representation. The App Store will then compile the bitcode down into the 64 or 32 bit executables as necessary.

也就是

当我们提交程序到 App Store上时, Xcode 会将程序编译为一个中间表现形式( bitcode )。然后 App store 会再将这个 bitcode 编译为可执行的64位或32位程序。

请看这里 http://blog.csdn.net/soindy/article/details/48518717

如果你的应用也准备启用 Bitcode 编译机制,就需要注意以下几点:

Xcode 7默认开启 Bitcode ,如果应用开启 Bitcode,那么其集成的其他第三方库也需要是 Bitcode编译的包才能真正进行 Bitcode 编译

开启 Bitcode 编译后,编译产生的 .app 体积会变大(中间代码,不是用户下载的包),且 .dSYM文件不能用来崩溃日志的符号化(用户下载的包是 Apple 服务重新编译产生的,有产生新的符号文件)

通过 Archive 方式上传 AppStore 的包,可以在Xcode的Organizer工具中下载对应安装包的新的符号文件

出现的问题原因是什么呢?

原来是某些二进制库不支持bitcode.而Xcode默认是要支持bitcode的,而且如果支持的话,其中所有的二进制库和framework都必须包含bitcode.

怎么样解决呢?

我们可以直接将bitcode直接关掉就可以了。target —> Built Seeting —>搜索 bitcode —>将Yes置为No
---------------------
作者:ismilesky
来源:CSDN
原文:https://blog.csdn.net/ismilesky/article/details/50721365
版权声明:本文为博主原创文章,转载请附上博文链接!

Filed under: Mac OS Comments Off
23Oct/18

如何隐藏SDK中(.a库之间的冲突)符号 iOS/C/C++

Posted by Nick Xu

一、 问题引入

在当下的开发中,应用的功能做的越来越复杂,工程也越来越大,所以为了

尽可能缩短开发周期,不可避免的会用到许多第三方库,随之而来的也会遇到好

多问题。比如,程序调用函数funa,funa函数从在于两个库liba.a,libb.a中,

并且程序执行需要连接这两个库,那么程序执行时是调用liba.a中funa还是调用

的libb.a中的funa呢?

其实这个取决于链接时的顺序,比如先链接的liba.a,这个时候通过liba.a的导出符号表就可以找到funa在liba.a中定义,并加入符号表中;链接libb.a的

时候发现符号表已经存在funa,就不会再次更新符号表,所以调用的始终是liba.a中的funa函数。

这里的调用严重的依赖于链接库加载的顺序,很大程度上会导致混论。作为SDK的提供者,我们尤其要避免这点。

正常我们使用的库中包含了好多符号信息,如图1所示:

图1

这些符号信息有以下几个弊端:

1、增大了库的体积;

2、隐蔽性较差;

3、容易带来冲突。在开发过程中第三点带来的问题尤其严重,特别是当我们提供的SDK用到第

三方库的时候(因为使用我们SDK的客户也有可能用到跟我们一样的第三方库)。

二、 解决办法

1、对第三方库处理  (C/C++)

下面继续以x264(下文以libx264.a带过)为例说明如何编译第三方的库。

没有隐藏符号的第三方库如“图1”所示,函数前面会带有external的标示。

在最终对外发布的SDK中_x264_predict_16x16_dc_c还是打着external的标签,

及对外可见。如图2所示:

图2

隐藏符号后,在libx264.a中,原先打上external标签的函数,会以private external标识。如图3所示:

图3

那么如何才能得到我们想要的、打上private external标签的库呢,有两种方

法可以做到。

1)对每个函数加属性__attribute__((visibility(“hidden”))) void funa_hidden()

{

printf(“hidden symbol\n”);

}

void funa_visible()

{

printf(“exported symbol”);

}

这样做的好处是可以根据需要对每个函数做定制处理。但若我们用到的三方库代码量大,这种方法就是费时费力了。

2)编译库时统一处理

利用gcc的扩展属性,编译库时加上-fvisibility=hidden。

a)静态库

gcc –static –o libtest.a –fvisibility=hidden –c test.c

b)动态库

gcc –dynamic –o libtest.so –fvisility=hidden –c test.c,其中dynamic为clang的写法,大部分gcc写法为shared。

上边两种方法只处理了c/c++,因为语法问题,汇编需要做特殊里,但也是在函数头加属性,但它的属性写法为.private_extern。.macro function name, export=0, align=2

.macro endfunc

ELF .size \name, .

- \name

FUNC .endfunc

.purgem endfunc

.endm

.text

.align \align

.if \export

.global EXTERN_ASM\name

ELF .type EXTERN_ASM\name, %function

FUNC .func EXTERN_ASM\name

EXTERN_ASM\name:

.private_extern

EXTERN_ASM\name

.else

ELF .type

FUNC .func    \name:   .endif

.endm

\name, %function

\name

因为需要处理的汇编文件较少,所以对汇编采用了直接编辑源文件的方法。

其实个人觉得也应该能在编译时做统一处理,有兴趣的可以自己找一下方法。

2、对xcode工程的处理 (iOS)

对xcode工程处理相对直观、简单了许多。只需在工程的设置里做如下处理。

1)打开工程设置,跳转到build setting页面;

2)搜索hidden;

3)将Symbols Hidden by Default设置Yes;

图4

其实通过观察编译的过程可以发现,通过上述设置,苹果最终将其转化为步

骤1的命令进行编译。编译的结果也是在库里加了private external而已。

3、符号剥离

最后一步,也是最关键的一步,就是真正将步骤1或步骤2中打上private

external标签的函数做最终的处理,把它们从要发布的库里剥离。

1)首先设置prelink

在target的build setting里搜索prelink,将Perform Single-Object Prelink置为

Yes,然后把该工程需要的库都直接拖到Prelink libraries中。如图5所示:

图5

2)设置 post process

将Deployment Postprocessing置为Yes。如图6所示:

图6

3)设置剥离方式

将Strip Style设置为Non-Global Symbols。如图7所示:

图7

到目前为止,所有的设置都已经完成,接下来编译。有兴趣的同学可以观察

一下编译的过程,会发现通过设置prelink,xcode会将库里所有的目标文件根据

你支持的architecture分类打包,如libxxx-armv7-master.o/libxxx-arm64-master.o,

最后一步执行Strip命令将所有需要隐藏的符号剥离。

作者:atme
链接:https://www.jianshu.com/p/761fca990325
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Filed under: Mac OS Comments Off
site
site