关于编译:关于编译的重要概念总结

回忆初学编程的时候,大部分人都是从C语言开始学起的,除了一些常见的语法和思维,一些基础知识经常被人们疏忽,如果没有及时地进行梳理,可能短时间内没有太大的影响,然而在日后碰到这些问题时仍旧一头雾水。例如C语言是一门编译型语言,编译型语言首先将源代码编译生成机器语言,再由机器运行机器码(二进制)。对于编译型语言,绕不过的就是编译器。 上面提出几个问题,无妨思考一下: 什么是GNU什么是GCC / G++什么是MinGW-w64C++ 规范有哪些?次要区别是什么?Makefile是什么?cmake是什么?如果脑海中没有一个整体的概念框架的话,正如那张图,一个全副武装的骑士,尽管防护的很好,然而对于编译器的基础知识把握的不牢,就像头盔上的一个缝隙,可能下一箭正中缝隙,败下阵来。 上面具体介绍这几个概念: 什么是GNUGNU 是一个打算或者叫静止。在这个旗号下成立了 FSF,起草了 GPL 等。 GNU操作系统是一种由自由软件形成的类 Unix 操作系统,该零碎基于 Linux 内核,指标在于建设一个齐全相容于UNIX的自由软件环境。 过后Unix 零碎开始免费和商业闭源了。针对这一景象,Richard Stallman发动了 GNU 打算,模拟 Unix 的界面和应用形式,从头做一个开源的版本。他本人做了编辑器 Emacs 和编译器 GCC。接下来开发者实现了包含外围的 gcc 和 glibc。然而 GNU 零碎短少操作系统内核。原定的内核叫 HURD,始终完不成。同时 BSD(一种 UNIX 发行版)陷入版权纠纷,x86 平台开发暂停。这时 Linus 为了在 PC 上运行 Unix,在 Minix 的启发下,开发了Linux。当然 Linux 只是一个零碎内核,系统启动之后应用的依然是 gcc 和 bash 等软件。Linus 在公布 Linux 的时候抉择了 GPL,因而合乎 GNU 的主旨。也补救了GNU在这方面的短少,于是合在一起打包公布叫 GNU / Linux。而后省掉了后面局部,变成了 Linux 零碎。实际上 Debian,RedHat 等 Linux 发行版中内核只占了很小一部分容量。 参考:https://www.gnu.org/gnu/gnu-linux-faq.html 什么是GCC / G++GCC(GNU编译器套件):GNU Compiler Collection。能够编译C、C++、JAVA、Fortran、Pascal、Object-C、Ada等语言。 ...

April 3, 2023 · 1 min · jiezi

关于编译:龙智宣布与Incredibuild建立战略合作伙伴关系

近日,龙智发表与当先的减速编译软件提供商Incredibuild建设策略合作伙伴关系。 Incredibuild是一款减速编译工具。凭借其独特的过程虚拟化技术(Vritualized Distributed Processing™),使用户可能轻松地减速代码构建、测试和许多其余耗时的开发工作,可显著进步一系列编译工作和开发工具的性能,缩短开发工夫并放慢产品交付。 龙智是一家DevSecOps研发平安经营一体化解决方案供应商,致力于为中国企业集成寰球受欢迎的工具,并通过个性化的开发帮忙企业量身打造DevSecOps解决方案,助力企业晋升研发管理水平。 在数字化转型的浪潮下,所有企业都须要减速交付。在这样的背景下,单方达成策略单干,旨在帮忙中国企业缩短研发周期,升高研发老本,进步研发效率与品质。 Incredibuild方示意:“咱们很快乐地发表,咱们曾经与龙智公司正式成为合作伙伴。这是一次极具后劲的单干,将使咱们可能利用彼此的专业知识和资源,独特为客户提供更疾速、更高效的解决方案。咱们期待着与龙智的单干获得更大的成就,并为客户带来更优质的体验。" ”通过与Incredibuild建设策略合作伙伴关系,可能进一步欠缺和降级龙智DevSecOps研发平安经营一体化解决方案。Incredibuild的当先技术能减速编译和构建过程,为客户带来更高效的体验。让开发人员可能跨平台、跨行业和跨环境开启麻利。”龙智董事长何明说,“同时,咱们也在不断创新和扩大龙智的DevSecOps解决方案,期待着与Incredibuild独特引领行业实际,帮忙中国企业更好、更快地交付软件。” 龙智将提供Incredibuild产品从征询、计划定制、我的项目配置、施行部署、规范/定制化培训、到运维的一站式服务。 此前,龙智曾经与Atlassian、Perforce、CloudBees、Mend(原WhiteSource)、SmartBear等寰球DevSecOps畛域出名厂商达成单干,为企业提供事务与我的项目追踪软件Jira,企业Wiki与文档协同软件Confluence,版本控制系统Helix Core,动态代码剖析工具Klocwork,动态测试工具Helix QAC,被称为企业版Jenkins的CI/CD平台CloudBees,开源代码平安扫描工具Mend,自动化测试工具TestComplete、ReadyAPI等,并围绕这些工具提供一站式的服务*,包含: 疾速精确地评估、验证规范产品是否满足客户理论业务需要,是否须要插件或二次开发反对等咨询服务;规范培训服务(包含用户应用培训、我的项目配置管理培训、系统管理培训等),也可依据客户的理论需要,针对具体模块的性能,结合实际利用场景等提供定制化培训服务,解决用户痛点;标准化的二次开发培训服务,以及具体业务需要的二次开发服务;基于客户理论业务需要,交付开箱即用的我的项目配置服务;针对规范产品,提供5* 8小时的中文在线技术支持服务;软件版本的部署、降级以及迁徙服务;基于客户需要提供插件举荐、售前介绍、试用、代其与插件厂商沟通等服务,针对市场罕用插件、我司自研插件等还可提供插件演示、培训等服务。*针对不同产品,具体服务内容不同。详情请征询龙智。对于龙智龙智是一家DevSecOps解决方案提供商,专一于软件开发经营一体化畛域十多年,集成DevSecOps、ITSM、Agile治理思路及该畛域的优良工具,提供从产品布局与需要治理、开发,到测试、部署以及运维全生命周期的解决方案,通过业余征询、计划定制、施行部署、专业培训、定制开发等一站式服务,帮忙企业实现软件开发经营一体化,并确保安全防护融入软件研发的整个生命周期中。龙智在日本东京、加拿大滑铁卢、在中国香港和上海均设有办公室,服务寰球客户。 凭借继续深耕、不断创新的精力,龙智的解决方案先后取得了金融、汽车、通信、游戏、互联网、芯片等行业1000多家企业的认可与信赖,被评为“高新技术企业”、“上海市‘专精特新’中小企业”。 对于Incredibuild Incredibuild可显著进步一系列编译工作和开发工具的性能,缩短开发工夫并放慢产品交付。凭借其独特的过程虚拟化技术(Vritualized Distributed Processing ™),使用户可能轻松地减速代码构建、测试和许多其余耗时的开发工作。 Incredibuild受2000多个组织的100000多名用户的信赖,是构建减速的事实标准。Incredibuild为各种商业和外部工具提供解决方案,如Visual Studio编译减速、通用构建工具、测试、代码剖析和自产高吞吐量计算。代码构建、测试、脚本、自产应用程序和间断交付构建都是Incredibuild能够减速的一些过程例子。

February 10, 2023 · 1 min · jiezi

关于编译:python项目编译加密

有些时候处于代码窃密的要求,会须要把python代码进行加密或者编译加密等来实现窃密 原理Python是一种面向对象的解释型计算机程序设计语言,解释个性是将py编译为独有的二进制编码*.pyc文件,对pyc中的指令进行解释执行,然而pyc的反编译非常简单,可间接反编译为源码因为基于虚拟机(解释型语言)的编程语言比方java或者python很容易被人反编译,因而越来越多的利用将其中的外围代码以C/C++为编程语言,并且以*.so文件的模式提供在windows环境上面常常会看到*.dll文件,在Linux环境下常常会看到*.so文件,这两种都是动静库,*.so文件能够称为动态链接库或者共享库,是ELF文件格式,也是一种二进制文件,个别是C或者C++编译进去的尽管目前有一些反编译伎俩能够去反编译so文件,然而如同成果都不怎么样,反编译进去的都是一堆比拟凌乱的C语言代码,咱们是用python编写的程序,所以把Python代码打包成so文件是能够达到加密的要求的 技术依赖开源我的项目Nuitka,采纳Apache-2.0 license协定 装置nuitkapip形式 python -m pip install -U nuitka在Ubuntu22上面应用python3.10是能够胜利装置的,其余操作系统或者python版本如果装置失败 请具体浏览官网nuitka装置文档,外面蕴含了apt,yum模式的装置 单文件编译以下局部来源于nuitka官网文档 创立一个hello.py def talk(message): return "Talk " + messagedef main(): print(talk("Hello World"))if __name__ == "__main__": main()当前目录文件为 $ ll总用量 4.0K-rw-rw-r-- 1 gong gong 133 九月 22 12:52 hello.py开始编译因为之前是采纳pip形式装置的nuitka,所以应用的时候须要带上python -m的前缀 如果是应用apt或者yum等装置的,间接运行nuitka或者nuitka3即可 运行如下命令能够在当前目录上面创立一个hello.bin的文件 $ python -m nuitka hello.py --remove-output....参数解释--remove-output参数示意在生成二进制编译文件之后移除编译构建目录,该目录是编译过程中会应用到,编译完结之后即可删除 运行二进制文件$ ./hello.binTalk Hello World我的项目级别编译上面采纳django我的项目进行演示,出于不便采纳sqlite数据库,生产环境请应用其余数据库 创立示范我的项目$ pip install django -i https://pypi.doubanio.com/simple/$ django-admin startproject hellonuitka$ cd hellonuitka$ python manage.py migrate$ python manage.py runserver查看初始门路树(tree能够通过sudo apt/yum install tree装置) ...

September 23, 2022 · 3 min · jiezi

关于编译:故障分析-MySQL-57-使用临时表导致数据库-Crash

作者:雷文霆 爱可生华东交付服务部 DBA 成员,次要负责Mysql故障解决及相干技术支持。喜好看书,电影。座右铭,每一个未曾起舞的日子,都是对生命的辜负。 本文起源:原创投稿 *爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。 目录背景信息故障剖析问题复现测试日志测试论断参考链接背景信息在 MySQL5.7.30 主从读写拆散环境下,从库在某天呈现了 MySQL crash. 零碎侧: 监控显示该从库主机的内存和CPU资源使用率在故障前后均失常,磁盘IO有2%的iowait(读写200M/s),阐明故障前磁盘存在压力。 服务侧:slow-log 中记录了服务重启前,存在应用了长期表和文件排序的慢 SQL 语句。 Error-log 中记录了服务调用到 btr0btr.cc 文件 的 L2165 行,呈现了 err == DB_SUCCESS 报错。 0x7f2dd49d0700 InnoDB: Assertion failure in thread 139834817316608 in file btr0btr.cc line 2165InnoDB: Failing assertion: err == DB_SUCCESSInnoDB: We intentionally generate a memory trap.InnoDB: Submit a detailed bug report to http://bugs.mysql.com.故障剖析在零碎侧排除了磁盘空间有余和内存不足的因素,服务侧狐疑是慢查问和BUG的起因,之后通过" btr0btr.cc"关键字查找到了一个相似的 BUG 。链接如下: https://bugs.mysql.com/bug.ph...报告的意思是,MySQL 在执行 btr_insert_on_non_leaf_level_func()函数时,写入长期表会导致带有断言的服务解体。 通过查看 btr0btr.cc 文件结尾的正文理解到的起因是: 此文件的调用机制是:对b树行操作或记录所做的所有更改。 L2165 行操作内容是:在解决插入到非叶级别的内容时,会查看每个级别的可用空间(需保留2倍索引数高度的页空间),如果在操作之前,叶决裂曾经开始,就很难撤销,只能通过解体进行前滚。该 BUG 只会在 MySQL5.7 呈现 ...

May 13, 2022 · 4 min · jiezi

关于编译:南京大学编译实验-Lab-3-自动测试脚本NJU编译原理课程-C-语言实验的-irsimpyc-虚拟机小程序自动化执行

南京大学编译试验 Lab 3 自动测试脚本文章版权属于 法华寺中班小屁孩 @ 博客园 (也就是我),未经作者容许,禁止转载。文章地址 https://www.cnblogs.com/stupi...GitHub: StupidPanther本文将贴出用于编译试验3的自动测试脚本源码。 波及版权,本文将不会提供 irsim.pyc 虚拟机小程序和任何官网测试样例。 脚本的运行须要配置python3等环境,置信对于大家来说不是问题,后文也会对环境配置给予探讨。 OK,进入正题。首先明确,本脚本判断测试是否正确的规范 是:执行你的编译器编译失去的IR程序,是否能产生预期的输入。 本地文件构造应用脚本自动测试,须要依照如下所示组织本地文件构造: .├── auto_run_irsim.py # 与运行irsim.pyc相干的脚本├── run.py # 自动化测试脚本,即你要执行的脚本├── irsim.pyc -> /home/me/Compiler/irsim/irsim.pyc # 链接到irsim.pyc的软链接├── expects # 你冀望的输入(即执行C--编译器输入的IR文件所冀望的输入)│   └── doc.1.1.expect├── inputs # 测试样例(用C--语言编写)│   └── doc.1.1.cmm├── irs # 编译测试样例失去的IR文件(该文件夹无需事后新建)├── outputs # 执行IR程序的理论输入(该文件夹无需事后新建)└── texts # 执行IR程序所对应的stdin(即执行IR程序时本须要手工输出的数据) └── doc.1.1.textrun.py和auto_run_irsim.py的代码将在稍后贴出。接下来将会解释inputs,texts,expects文件夹中的文件应如何筹备(即如何筹备测试样例)。 筹备测试样例须要筹备好inputs,texts,expects文件夹。 inputs文件夹:C--语言源程序无需多说,C--语言源程序合乎试验手册要求即可。须要留神,inputs文件夹中的文件名(不含后缀)须要与texts和expects文件夹中对应的文件雷同,正如上文中的文件结构图所示。 上面给出一个示例:doc.1.1.cmm。 int main(){ int a; int b; read(a); b = a + 1; write(b); return 0;}texts文件夹:执行IR程序须要的stdin内容(即本需手工输出的数据)C--语言源程序中如果调用了read函数,那么,在执行其对应的IR时,须要手工输出数据,这里将本应手工输出的数据写在texts文件夹中后缀为.text的文件中。 留神:每个数据均以换行符完结,文件的后缀必须为.text。 ...

May 6, 2022 · 4 min · jiezi

关于编译:hyengine-面向移动端的高性能通用编译解释引擎

简介:手机淘宝客户端在历史上接过多种多样的脚本引擎,用于反对的语言包含:js/python/wasm/lua,其中js引擎接过的就有:javascriptcore/duktape/v8/quickjs 等多个。泛滥的引擎会面临独特面临包大小及性能相干的问题,咱们是否能够提供一套计划,在能反对业务需要的前提下,用一个引擎来反对尽可能多的语言,能较好的兼顾包大小较小和性能优异。为了解决这个问题,咱们开始了 hyengine 的摸索。 作者 | 知兵起源 | 阿里技术公众号 一 背景简介手机淘宝客户端在历史上接过多种多样的脚本引擎,用于反对的语言包含:js/python/wasm/lua,其中js引擎接过的就有:javascriptcore/duktape/v8/quickjs 等多个。泛滥的引擎会面临独特面临包大小及性能相干的问题,咱们是否能够提供一套计划,在能反对业务需要的前提下,用一个引擎来反对尽可能多的语言,能较好的兼顾包大小较小和性能优异。为了解决这个问题,咱们开始了 hyengine 的摸索。 二 设计简介"有hyengine就够全家用了" - hyengine是为对立挪动技术所需的各种脚本语言(wasm/js/python 等)执行引擎而生,以轻量级、高性能、多语言反对为设计和研发指标。目前已通过对 wasm3/quickjs 的 jit 编译及 runtime 优化,以极小包体积的代价实现了 wasm/js 执行速度 2~3 倍的晋升,将来将通过实现自有字节码和 runtime 减少对 python 及其他语言的反对。 注:因为以后手机绝大多数都已反对 arm64,hyengine 仅反对 arm64 的 jit 实现。 注:因为 ios 不反对 jit,目前 hyengine 只有 android 版本。 hyengine 整体分为两大块,编译(compiler)局部及引擎(vm)局部。 compiler 局部分为前端、中端、后端,其中前端局部复用现有脚本引擎的实现,比方 js 应用 quickjs,wasm 应用 emscripten,中端打算实现一套本人的字节码、优化器及字节码转换器,后端实现了 quickjs 和 wasm 的 jit 及汇编器和优化器。 vm 分为解释器、runtime、api、调试、根底库,因为人力无限,目前VM暂无残缺的自有实现,复用quickjs/wasm3 的代码,通过实现一套本人的内分配器及gc,和优化现有runtime实现来晋升性能。 业务代码(以wasm为例)通过下图所示的流程,被编译为可执行代码: ...

January 6, 2022 · 17 min · jiezi

关于编译:程序人生-Makefile-常用模板-静态链接库动态链接库可执行文件

本文首发于 2014-07-10 11:51:10前言本文把 makefile 分成了三份:生成可执行文件的 makefile,生成动态链接库的 makefile,生成动态链接库的 makefile。 这些 makefile 都很简略,个别都是一看就会用,用法也很容易,只须要把它们拷贝到你的代码的同一目录下,而后就能够用 make 来生成指标文件了。 上面是三个makefile的源代码:  生成可执行文件的 makefile##############################################################################source file#源文件,主动找所有.c和.cpp文件,并将指标定义为同名.o文件SOURCE := $(wildcard *.c) $(wildcard *.cpp)OBJS := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE))) #target you can change test to what you want#指标文件名,输出任意你想要的执行文件名TARGET := test #compile and lib parameter#编译参数CC := gccLIBS :=LDFLAGS :=DEFINES :=INCLUDE := -I.CFLAGS := -g -Wall -O3 $(DEFINES) $(INCLUDE)CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_H #i think you should do anything here#上面的基本上不须要做任何改变了.PHONY : everything objs clean veryclean rebuild everything : $(TARGET) all : $(TARGET) objs : $(OBJS) rebuild: veryclean everything clean : rm -fr *.so rm -fr *.o veryclean : clean rm -fr $(TARGET) $(TARGET) : $(OBJS) $(CC) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LIBS)生成动态链接库的 makefile############################################################################## #target you can change test to what you want#共享库文件名,lib*.aTARGET := libtest.a #compile and lib parameter#编译参数CC := gccAR = arRANLIB = ranlibLIBS :=LDFLAGS :=DEFINES :=INCLUDE := -I.CFLAGS := -g -Wall -O3 $(DEFINES) $(INCLUDE)CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_H #i think you should do anything here#上面的基本上不须要做任何改变了 #source file#源文件,主动找所有.c和.cpp文件,并将指标定义为同名.o文件SOURCE := $(wildcard *.c) $(wildcard *.cpp)OBJS := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE))) .PHONY : everything objs clean veryclean rebuild everything : $(TARGET) all : $(TARGET) objs : $(OBJS) rebuild: veryclean everything clean : rm -fr *.o veryclean : clean rm -fr $(TARGET) $(TARGET) : $(OBJS) $(AR) cru $(TARGET) $(OBJS) $(RANLIB) $(TARGET)生成动态链接库的 makefile############################################################################## #target you can change test to what you want#共享库文件名,lib*.soTARGET := libtest.so #compile and lib parameter#编译参数CC := gccLIBS :=LDFLAGS :=DEFINES :=INCLUDE := -I.CFLAGS := -g -Wall -O3 $(DEFINES) $(INCLUDE)CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_HSHARE := -fPIC -shared -o #i think you should do anything here#上面的基本上不须要做任何改变了 #source file#源文件,主动找所有.c和.cpp文件,并将指标定义为同名.o文件SOURCE := $(wildcard *.c) $(wildcard *.cpp)OBJS := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE))) .PHONY : everything objs clean veryclean rebuild everything : $(TARGET) all : $(TARGET) objs : $(OBJS) rebuild: veryclean everything clean : rm -fr *.o veryclean : clean rm -fr $(TARGET) $(TARGET) : $(OBJS) $(CC) $(CXXFLAGS) $(SHARE) $@ $(OBJS) $(LDFLAGS) $(LIBS)欢送关注我的微信公众号【数据库内核】:分享支流开源数据库和存储引擎相干技术。 ...

September 25, 2021 · 2 min · jiezi

关于编译:第39问如何编译-MySQL-的调试版本

问咱们在第16问中应用过 mysql 内置的调试版本 mysqld-debug ,但有些 MySQL 版本中没有内置的调试版本. 这次介绍一下如何编译一个调试版本 试验咱们先筹备一个装置了 docker 的环境, 之所以用容器, 是因为咱们在进行各种试验后, 能够将容器毁掉重建, 放弃零碎环境洁净对立, 十分便当. 首先开启一个 devtoolset 容器: 确认本人在容器内: 下载 MySQL 源码包并解压: 接下来装置依赖包, 一共分为 3 类依赖: 编译用的工具, MySQL 的依赖包, 以及开启 DTRACE 调试性能用的依赖包 (DTRACE 调试性能 咱们当前会介绍) 创立一个 build 目录, 之后 MySQL 会将编译的过程文件和后果都放在这个文件夹里: 对编译进行配置: 在一大段输入后, 能够看到配置胜利的信息: 当初能够正式编译了: 通过漫长的五彩斑斓的输入, 编译顺利胜利: 在 build/sql 文件夹中, 曾经造成了调试版的 mysqld : 小贴士 如何像官网一样编译正式的 MySQL ? 在配置环节, cmake 命令中, 将 -DWITH_DEBUG=1 换成 -DBUILD_CONFIG=mysql_release 即可 ...

June 18, 2021 · 1 min · jiezi

关于centos7:20200323-Centos7下当前最高版本python392源码编译安装方法

2020-03-23 Centos7下以后最高版本python3.9.2源码编译装置办法日期作者版本备注2021-03-22dingbinV1.0 本文概要记录Centos7下python3.9.2源码编译装置办法。操作日期: 2021-03-23.操作环境:CentOS Linux release 7.5.1804, 16核 20G具体操作办法如下:官网下载以后最新最高版本python release包:Python-3.9.2.tar.xz编译装置:Python-3.9.2.tar.xztar xvf Python-3.9.2.tar.xz cd Python-3.9.2./configure --prefix=/home/xx/app/python39 --enable-shared --enable-optimizations #留神:--enable-shared 十分重要,因为这个选项会编译出动静python链接库,供其余程序调用,比方编译vim大牛补全插件YouCompleteMe或Vim高版本时,就依赖动静python链接库。 此时必须要加--enable-shared 这个选项,否则python须要从新编译装置。make PROFILE_TASK=" -m test.regrtest --pgo -j14 " -j14make install全副过程大概10分钟左右实现。 精要配置python 将/home/xx/python39/ 退出~/.bashrc 中PATH环境变量cd /home/xx/python39/binln -sf pip3 pipln -sf easy_install-3.9 easy_install3ln -sf easy_install-3.9 easy_installln -sf python3.9 pythonvim ~/.pip/pip.conf退出如下内容:[global]timeout = 10000index-url=http://pypi.douban.com/simpleextra-index-url=http://mirrors.aliyun.com/pypi/simple/#extra-index-url=https://pypi.tuna.tsinghua.edu.cn/simple/#extra-index-url=http://pypi.mirrors.ustc.edu.cn/simple/[install]trusted-host=pypi.douban.com#trusted-host=mirrors.aliyun.com#trusted-host=pypi.tuna.tsinghua.edu.cn#trusted-host=pypi.mirrors.ustc.edu.cn保留退出。pip install virtualenv virtualenvwrapperpip --upgrade install pipvim ~/.bashrc 退出:export WORKON_HOME=${HOME}/.virtualenvsexport PROJECT_HOME=${HOME}/work/projects/pythonprojects.gitexport VIRTUALENVWRAPPER_PYTHON=${PYTHON39_HOME}/bin/pythonsource ${PYTHON39_HOME}/bin/virtualenvwrapper.s保留退出。从新source ~/.bashrcworkon 能够看目前有哪些虚构python环境,workon xxx 进入某个虚构python环境mkvirtualenv -p ~/app/python39/bin/python --copies newvenv1 创立某个虚构python环境名叫newvenv1deactivate 退出以后环境操作示例如下图所示: ...

March 23, 2021 · 1 min · jiezi

关于编译:手撸golang-行为型设计模式-解释器模式

手撸golang 行为型设计模式 解释器模式缘起最近温习设计模式拜读谭勇德的<<设计模式就该这样学>>本系列笔记拟采纳golang练习之 解释器模式解释器模式(Interpreter Pattern)指给定一门语言,定义它的文法的一种示意,并定义一个解释器,该解释器应用该示意来解释语言中的句子。解释器模式是一种依照规定的文法(语法)进行解析的模式,属于行为型设计模式。(摘自 谭勇德 <<设计模式就该这样学>>)场景某业务零碎, 随数据量减少, 数据库拜访压力日渐增大业务team心愿平台team提供通明的缓存解决方案以缓解数据库压力平台team经重复探讨钻研, 决定采纳解释器模式, 间接拦挡/解析/执行SQL(子集)语句, 提供透明化缓存服务SQL(子集)文法SQL: select + FIELD_LIST + from TABLE_NAME + (where BOOL_EXPRESSION)? FIELD_LIST: * | COLUMN_LIST COLUMN_LIST: COLUMN_NAME + (,COLUMN_NAME)* COLUMN_NAME: IDENTIFIER IDENTIFIER: [_a-zA-Z] + [_a-zA-Z0-9]*TABLE_NAME: IDENTIFIER BOOL_EXPRESSION: STRING_FIELD = STRING_LITERAL | STRING_FIELD <> STRING_LITERAL | STRING_FIELD like STRING_LITERAL | STRING_FIELD not like STRING_LITERAL | INT_FIELD = INT_LITERAL | INT_FIELD <> INT_LITERAL | INT_FIELD > INT_LITERAL | INT_FIELD >= INT_LITERAL | INT_FIELD < INT_LITERAL | INT_FIELD <= INT_LITERAL | ( + BOOL_EXPRESSION + ) | BOOL_EXPRESSION and BOOL_EXPRESSION | BOOL_EXPRESSION or BOOL_EXPRESSION STRING_FIELD: IDENTIFIER INT_FIELD: IDENTIFIER STRING_LITERAL: \' + [^"]* + \' INT_LIETRAL: [1-9] + [0-9]*设计IDatabase: 数据库接口IDataTable: 数据表接口IDataRow: 数据行接口IDataField: 数据字段接口IRowFilter: 数据行过滤器接口tEmptyRowFilter: 动态为true/false的行过滤器tExpressionRowFilter: 基于布尔表达式的行过滤器Tokens: SQL(子集)记号枚举Nodes: SQL(子集)语法树节点枚举Chars: 词法剖析辅助类ISQLParser: SQL(子集)词法分析器接口Lexer: 词法剖析实现Parser: 语法分析实现, SQL(子集)解释器的外围tTokenQueue: 词法节点队列tArrayStack: 基于数组实现的LIFO堆栈IBoolExpression: 布尔表达式接口tFieldExpression: 基于字段计算的布尔表达式tLogicExpression: 基于关系(AND/OR)计算的布尔表达式SaleOrder: 销售订单实体类ISaleOrderService: 销售订单服务接口, 继承自IDataTable接口tMockDatabase: 虚构的数据库服务, 实现IDatabase接口tMockSaleOrderService: 虚构的销售订单服务, 实现ISaleOrderService接口单元测试interpreter_pattern_test.go, 模仿销售订单的保留与SQL查问 ...

February 13, 2021 · 14 min · jiezi

关于编译:多媒体开发7编译Android与iOS平台的FFmpeg

编译FFmpeg,一个古老的话题,但我还是介绍一遍,就当记录。之前介绍怎么给视频增加水印时,就曾经提到FFmpeg的编译,并且在编译时指定了滤镜的性能。 然而,在手机流行的时代,你可能更须要的是能在iOS或Android平台上运行的FFmpeg,而对于命令行的ffmpeg,你能够在个人电脑下面应用(因为它简洁易操作),也能够在服务程序中应用(装置FFmpeg后间接调用ffmpeg命令),比方小程常常在本人的mac机上应用ffmpeg命令。 本文介绍怎么编译出iOS或Android平台应用的FFmpeg链接库。 正如编译macos平台应用的FFmpeg一样,编译iOS或Android平台应用的FFmpeg,主线也是先configure再make,只不过,有更多的细节须要思考。 我应用的是macos零碎,以下介绍的就是在mac上穿插编译,编译出挪动平台应用的FFmpeg。 (1)编译环境筹备pkg-configFFmpeg在编译时常常应用到第三方库(比方x264、rtmp等),编译器在查找这些第三方库的头文件与库文件时,须要应用到程序pkg-config。 pkg-conifig给编译器提供门路与链接选项。第三方库在make install时会生成pc后缀的文件并拷贝到系统目录,而pkg-config就是从这个pc文件读取出门路信息。 能够设置PKG_CONFIG_PATH这个环境变量,指定目录,让pkg-config到这个目录上面去找pc文件,如果不设置,则默认在/usr/local/lib/pkgconfig目录上面查找,比方某个时刻我的pkgconfig目录上面是这样的一堆pc文件: 这样装置pkg-config: brew install pkg-config装置pkg-config后,能够这样获取第三方库的门路信息: pkg-config --cflags --libs freetype2以下是对于pkg-config命令的一个载图: 须要留神,尽管pkg-config查找到的pc文件外面有记录到第三方动态库的门路,但理论在编译FFmpeg动态库时,并不会链接上这个第三方库,而且在FFmpeg的编译脚本中能够指定第三方库的门路。 freetype此项只在应用滤镜性能时须要装置。 如果编译时遇到这样的提醒:freetype2 not found using pkg-config,那阐明还没有装置freetype,这样装置即可: brew install freetypeclang编译器此项只在编译iOS平台的FFmpeg时才须要。 因为我的mac机曾经装置过xcode,所以clang曾经存在。如果你的mac还没有装置clang的话,那倡议把xcode装置好。 asm编译器此项只在编译iOS平台的FFmpeg时才须要。 x264或FFmpeg等,都有汇编代码,编译这些汇编代码,须要应用更先进的编译脚本来解决,而mac零碎没有这样的脚本。 这个脚本是gas-preprocessor.pl。 能够这样下载并应用gas-preprocessor.pl: git clone git://github.com/mansr/gas-preprocessor.gitsudo cp -f gas-preprocessor/gas-preprocessor.pl /usr/local/bin/chmod +x /usr/local/bin/gas-preprocessor.plyasm另一个须要的工具是yasm汇编编译器,能够这样装置: brew install yasmNDK工具包此项只在编译Android平台的FFmpeg时才须要。 能够应用ndk-r9d版本,或者最新的版本,来编译FFmpeg,下载地址: https://developer.android.goo... (2)FFmpeg源码下载git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg(3)编译脚本不用本人重写了,找开源的我的项目过去批改一下(留神开源协定)就能够了,比方参考这个开源我的项目: https://github.com/yixia/FFmp... 在这个我的项目外面,有编译Android跟iOS平台的相应脚本,而且有相应的优化解决。在挪动平台应用的库都很重视两个货色,一个是性能,另一个是体积大小。一个好的脚本,既要依据不同的硬件类型作编译上的优化,也要依据软件需要裁剪FFmpeg的性能使得进去的库尽可能小(毕竟FFmpeg的性能并非全副都用上)。 (4)脚本批改小程先介绍一下脚本外面的一些要害参数,这些参数并非平台通用。 指定指令集: --extra-cflags='-arch armv7s' --extra-ldflags='-arch armv7s'指定cpu类型: --arch=arm --cpu=cortex-a9留神,应该依据不同的指令集应用不同的cpu优化;--arch=arm64,像这样指定具体指令架构也是能够的。 指定零碎: --target-os=darwin指定sdk: --sysroot=/Applications/Xcode.app/.../xxx.sdk指定编译器: --cc=xxx/clang指定库生成目录: --prefix=build指定应用的muxer/demuxer/encoder/decoder等: --enable-muxer=mp4基本上应用下面介绍的脚本就能够编译了,但有时候也能够作一些批改,比方要退出第三方库时,或者要对某个指令集作优化时,等等。 小程再提一些留神点,有可能帮你解决编译过程中遇到的问题: --sysroot须要指定。iOS平台为....sdk/,不包含usr/inclue;Android平台是编译链的目录。extra-cflags跟extra-ldflags要指定-arch(iOS)或-march(Android)。在xcode8.3.2(sdk为10.3)上,armv7/armv7s/arm64不能应用"-mfloat-abi=hard"选项,并且arm64要指定-mcpu=cortex-a53。在xcode9.2(sdk为11.2)上,须要--disable-asm。对于理论我的项目来说,FFmpeg的编译是要害的一步,应该多花工夫去钻研一些要害的细节--性能、性能跟体积大小都很重要。 (5)开始编译与应用运行脚本即可。最终会生成二进制库,比方iOS个别为动态库(.a文件),而Android个别为动静库(.so文件)。 ...

January 26, 2021 · 2 min · jiezi

关于编译:含有CGO代码的项目如何实现跨平台编译

目前小菜刀的我的项目中须要用到SQLite数据库,https://github.com/mattn/go-s...,采纳Go的标准接口有利于我的项目后续扩大,因而抉择了该驱动。然而,它是基于CGO实现的,所以跨平台编译会比拟麻烦,小菜刀总结了一些教训,特分享给读者敌人们。 什么是跨平台编译?简略地说, 就是在一个平台上生成另一个平台上的可执行代码。这里须要留神的是,所谓平台,实际上蕴含两个概念:体系架构(Architecture)、操作系统 (Operating System)。同一个体系架构能够运行不同的操作系统;同样,同一个操作系统也能够在不同的体系架构上运行。 咱们晓得Go语言是反对跨平台编译的,在之前的文章《Go穿插编译》中有具体介绍过怎么操作。Go实现跨平台编译的思维其实很简略:通过保留能够生成最终机器码的多份翻译代码,在编译时依据 GOARCH=xxx 和GOOS=xxx参数(对应体系架构和操作系统)进行初始化设置,最终调用对应平台编写的特定办法来生成机器码,从而实现跨平台编译。 CGO编译存在的问题有一点须要留神:Go所谓的跨平台编译只是针对Go代码局部,它是Go的穿插编译器(cross-compiler toolchains)。当咱们应用了CGO时,要想实现跨平台编译,同时须要让C/C++代码也反对跨平台。 package main/*#include <stdio.h>void printint(int v) { printf("printint: %d\n", v);}*/import "C"func main() { v := 42 C.printint(C.int(v))}小菜刀的开发机器:amd64架构,darwin零碎。指标编译平台:amd64架构,linux零碎。现想将上述含有CGO的代码编译为指标平台的可执行文件。 $ GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o main main.go通过以上命令,失去编译谬误如下 /usr/local/go/pkg/tool/darwin_amd64/link: running clang failed: exit status 1ld: warning: ignoring file /var/folders/xk/gn46n46d503dsztbc6_9qb2h0000gn/T/go-link-220081766/go.o, building for macOS-x86_64 but attempting to link with file built for unknown-unsupported file format ( 0x7F 0x45 0x4C 0x46 0x02 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 )Undefined symbols for architecture x86_64: "_main", referenced from: implicit entry/start for main executableld: symbol(s) not found for architecture x86_64clang: error: linker command failed with exit code 1 (use -v to see invocation)能够看到,因为CGO的存在,跨平台编译失败。那该如何解决呢? ...

January 11, 2021 · 3 min · jiezi

TypeScript 自动编译脚本的实现

引言万法归一,TypeScript似有一统前台的趋势。微信小程序也引入了TypeScript,我们也要跟随技术主流将小程序从JavaScript切换到TypeScript。微信小程序现在没之前那么火爆了,但仍我我们跨平台开发的明智。其实不管微信有小程序,支付宝、百度、QQ浏览器都相继上线小程序,还有手机联盟(vivo、oppo、华为等多家手机公司共同成立的)创建的快应用也狠狠地抄了腾讯一把,代码简直一模一样。小程序最火爆的时期要属去年清明节,小游戏横空出世,同时带火了小程序,周围的朋友都在用小程序、小游戏。记得当时还利用几天的假期时间,调用豆瓣开发的api,开发了一款名为豆瓣电影的小程序。可惜,最终没能上架,拒绝原因是该应用属于信息服务类的程序,禁止个人开发者申请。当时是使用ZanUI开发的,经历了一个自己玩的小项目,也算对微信小程序有了一个全面的理解。需求使用TypeScript重搭一次微信小程序的架子,今后的小程序使用TypeScript开发。实现基础工作建项目和之前没什么区别,就是在语言一栏需要选择TypeScript。其实使用TypeScript和JavaScript对于微信开发者工具来说没什么区别,用TypeScript也是编译成JavaScript再执行。这里不推荐直接使用微信开发者工具编写TypeScript,因为没有提示,我是采用WebStorm安装微信插件进行开发,然后打开微信开发者工具查看效果的。一路顺风,没什么问题。在UI框架选型上,我选择了ColorUI。为什么选择这个呢?虽然之前用过的ZanUI也很好用,也很全,但我第一眼看到ColorUI的时候,我被惊艳到了。再点进去组件查看,我猜想这个作者一定有过很多次的手机端页面开发经验,真的是每一个组件你都能用到,为作者点个赞。缺点就是文档不完善,但我认为这个Demo写得足够优秀了,直接clone下来,想要的都有了,剩下的就是改改字。希望以后当我有时间的时候,能给ColorUI的文档提交一些Pull Request,也算是感谢作者写出了这么好的UI库并分享给大众。非常好用,只需要去框架里粘一粘代码,漂亮的原型就出来了,挺好用的。自动编译写的时候遇到了点问题,就是编译的问题。微信开发者工具执行的是js文件,我编写的是ts文件,假设我修改了ts文件,我想看到修改后的效果,我需要手动编译,这就不优雅了。我们用过的grunt、ng,哪个不是自动编译、自动刷新?既然小程序没提供,那只能另谋生路了。突然想起ng不也是nodejs里的命令吗?它能监听文件自动编译,我为什么不试试看呢?nodenode.js不是一个框架,而是一个高效的JavaScript运行环境。所以,node.js脚本说到底就是一个js文件,没什么难的。在微服务中,我们常用node.js搭建反向代理服务器,其性能与nginx部分伯仲。自动化脚本新建脚本yunzhi.js,代码很简单,相信有编程基础的人都能看懂,这里就不再赘述。const exec = require(‘child_process’).exec;const watch = require(’node-watch’);watch([‘app.ts’, ‘specs’, ‘pages’], { recursive: true }, function(evt, name) { if (name.split(’.’).pop() === ’ts’) { console.log(‘监听到TypeScript文件改动,重新编译中…’); exec(’npm run compile’); }});console.log(‘云智TypeScript自动编译脚本已成功运行…’);总结不了解,就以为很难,其实当你勇敢地迈出第一步的时候,问题就已经解决。因为你觉得自己行,你真的就行。

March 27, 2019 · 1 min · jiezi

如何用cmake编译

本文由云+社区发表作者:工程师小熊CMake编译原理CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多。CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码生成可执行程序或共享库(so(shared object))。因此CMake的编译基本就两个步骤:cmakemakecompile.shg++ -rdynamic ../include/incl/tfc_base_config_file.cpp ../include/mq/*.cpp local_util.cpp AgentMemRpt.cpp AgentDiskRpt.cpp AgentLoadRpt.cpp AgentIoRpt.cpp AgentNetRpt.cpp AgentCpuRpt.cpp AgentProcessRpt.cpp AgentParentRpt.cpp AgentSysTop_5.cpp BaseFeatureRptMain.cpp -o rpt_main -I../include/incl -I../include/mq -I../include/rapidjson -lpthread -ldlCMake说明一般把CMakeLists.txt文件放在工程目录下,使用时,先创建一个叫build的文件夹(这个并非必须,因为cmake命令指向CMakeLists.txt所在的目录,例如cmake .. 表示CMakeLists.txt在当前目录的上一级目录。cmake后会生成很多编译的中间文件以及makefile文件,所以一般建议新建一个新的目录,专门用来编译),然后执行下列操作:cd build cmake .. make 其中cmake .. 在build里生成Makefile,make根据生成makefile文件,编译程序,make应当在有Makefile的目录下,根据Makefile生成可执行文件。编写 CMakeList.txt# 1. 声明要求的cmake最低版本cmake_minimum_required( VERSION 2.8 )# 2. 添加c++11标准支持#set( CMAKE_CXX_FLAGS “-std=c++11” )# 3. 声明一个cmake工程PROJECT(rpt_main)MESSAGE(STATUS “Project: SERVER”) #打印相关消息消息 # 4. 头文件include_directories(${PROJECT_SOURCE_DIR}/../include/mq ${PROJECT_SOURCE_DIR}/../include/incl ${PROJECT_SOURCE_DIR}/../include/rapidjson)# 5. 通过设定SRC变量,将源代码路径都给SRC,如果有多个,可以直接在后面继续添加set(SRC ${PROJECT_SOURCE_DIR}/../include/incl/tfc_base_config_file.cpp ${PROJECT_SOURCE_DIR}/../include/mq/tfc_ipc_sv.cpp ${PROJECT_SOURCE_DIR}/../include/mq/tfc_net_ipc_mq.cpp${PROJECT_SOURCE_DIR}/../include/mq/tfc_net_open_mq.cpp ${PROJECT_SOURCE_DIR}/local_util.cpp${PROJECT_SOURCE_DIR}/AgentMemRpt.cpp ${PROJECT_SOURCE_DIR}/AgentDiskRpt.cpp ${PROJECT_SOURCE_DIR}/AgentLoadRpt.cpp ${PROJECT_SOURCE_DIR}/AgentIoRpt.cpp${PROJECT_SOURCE_DIR}/AgentNetRpt.cpp ${PROJECT_SOURCE_DIR}/AgentCpuRpt.cpp ${PROJECT_SOURCE_DIR}/AgentProcessRpt.cpp ${PROJECT_SOURCE_DIR}/AgentParentRpt.cpp${PROJECT_SOURCE_DIR}/AgentSysTop_5.cpp ${PROJECT_SOURCE_DIR}/BaseFeatureRptMain.cpp )# 6. 创建共享库/静态库# 设置路径(下面生成共享库的路径)set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)# 即生成的共享库在工程文件夹下的lib文件夹中 set(LIB_NAME rpt_main_lib)# 创建共享库(把工程内的cpp文件都创建成共享库文件,方便通过头文件来调用)# 这时候只需要cpp,不需要有主函数 # ${PROJECT_NAME}是生成的库名 表示生成的共享库文件就叫做 lib工程名.so# 也可以专门写cmakelists来编译一个没有主函数的程序来生成共享库,供其它程序使用# SHARED为生成动态库,STATIC为生成静态库add_library(${LIB_NAME} STATIC ${SRC}) # 7. 链接库文件# 把刚刚生成的${LIB_NAME}库和所需的其它库链接起来# 如果需要链接其他的动态库,-l后接去除lib前缀和.so后缀的名称,以链接# libpthread.so 为例,-lpthreadtarget_link_libraries(${LIB_NAME} pthread dl) # 8. 编译主函数,生成可执行文件# 先设置路径set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) # 可执行文件生成add_executable(${PROJECT_NAME} ${SRC}) # 这个可执行文件所需的库(一般就是刚刚生成的工程的库咯)target_link_libraries(${PROJECT_NAME} pthread dl ${LIB_NAME})使用 cmake进入/home/pzqu/agent/libvirt_base_feature/build目录执行命令 cmake ..cmake ..查看生成的目录结构,此目录结构是中间代码,不用提交到git[root@TJSJZVM000456 /home/pzqu/agent/libvirt_base_feature/build]# tree.|– CMakeCache.txt|– CMakeFiles| |– 2.8.12.2| | |– CMakeCCompiler.cmake| | |– CMakeCXXCompiler.cmake| | |– CMakeDetermineCompilerABI_C.bin| | |– CMakeDetermineCompilerABI_CXX.bin| | |– CMakeSystem.cmake| | |– CompilerIdC| | | |– CMakeCCompilerId.c| | | -- a.out| | – CompilerIdCXX| | |– CMakeCXXCompilerId.cpp| | -- a.out| |-- CMakeDirectoryInformation.cmake| |-- CMakeOutput.log| |-- CMakeTmp| |-- Makefile.cmake| |-- Makefile2| |-- TargetDirectories.txt| |-- cmake.check_cache| |-- progress.marks| |-- rpt_main.dir| | |-- DependInfo.cmake| | |-- build.make| | |-- cmake_clean.cmake| | |-- depend.make| | |-- flags.make| | |-- home| | | – pzqu| | | -- agent| | | – include| | | |– incl| | | -- mq| | |-- link.txt| | – progress.make| -- rpt_main_lib.dir| |-- DependInfo.cmake| |-- build.make| |-- cmake_clean.cmake| |-- cmake_clean_target.cmake| |-- depend.make| |-- flags.make| |-- home| | – pzqu| | -- agent| | – include| | |– incl| | -- mq| |-- link.txt| – progress.make|– Makefile`– cmake_install.cmake使用make命令编译得到二进制文件make二进制文件所在目录(CMakeLists.txt文件配置)成功生成二进制文件下次教大家如何用Clion自动同步代码到服务器上,并进行debug此文已由腾讯云+社区在各渠道发布获取更多新鲜技术干货,可以关注我们腾讯云技术社区-云加社区官方号及知乎机构号 ...

March 13, 2019 · 2 min · jiezi

Go 程序是如何编译成目标机器码的

今天我们一起来研究 Go 1.11 的编译器,以及它将 Go 程序代码编译成可执行文件的过程。以便了解我们日常使用的工具是如何工作的。本文还会带你了解 Go 程序为什么这么快,以及编译器在这中间起到了什么作用。首先,编译器的三个阶段:逐行扫描源代码,将之转换为一系列的 token,交给 parser 解析。parser,它将一系列 token 转换为 AST(抽象语法树),用于下一步生成代码。最后一步,代码生成,会利用上一步生成的 AST 并根据目标机器平台的不同,生成目标机器码。注意:下面使用的代码包(go/scanner,go/parser,go/token,go/ast)主要是让我们可以方便地对 Go 代码进行解析和生成,做出更有趣的事情。但是 Go 本身的编译器并不是用这些代码包实现的。扫描代码,进行词法分析任何编译器的第一步都是将源代码文本分解成 token,由扫描程序(也称为词法分析器)完成。token 可以是关键字,字符串,变量名,函数名等等。每一个有效的词都由 token 表示。在 Go 中,我们写在代码上的 “package”,“main”,“func” 这些都是 token。token 由代码中的位置,类型和原始文本组成。我们可以使用 go/scanner 和 go/token 包在 Go 程序中自己执行扫描程序。这意味着我们可以像编译器那样扫描检视自己的代码。下面,我们将通过一个打印 Hello World 的示例来展示 token。package mainimport ( “fmt” “go/scanner” “go/token”)func main() { src := []byte(package mainimport "fmt"func main() { fmt.Println("Hello, world!")}) var s scanner.Scanner fset := token.NewFileSet() file := fset.AddFile("", fset.Base(), len(src)) s.Init(file, src, nil, 0) for { pos, tok, lit := s.Scan() fmt.Printf("%-6s%-8s%q\n", fset.Position(pos), tok, lit) if tok == token.EOF { break } }}首先通过源代码字符串创建 token 集合并初始化 scan.Scanner,它将逐行扫描我们的源代码。接下来循环调用 Scan() 并打印每个 token 的位置,类型和文本字符串,直到遇到文件结束(EOF)标记。输出:2:1 package “package"2:9 IDENT “main"2:13 ; “\n"4:1 import “import"4:8 STRING “"fmt"“4:13 ; “\n"6:1 func “func"6:6 IDENT “main"6:10 ( ““6:11 ) ““6:13 { ““7:2 IDENT “fmt"7:5 . ““7:6 IDENT “Println"7:13 ( ““7:14 STRING “"Hello, world!"“7:29 ) ““7:30 ; “\n"8:1 } ““8:2 ; “\n"8:3 EOF ““以第一行为例分析这个输出,第一列 2:1 表示扫描到了源代码第二行第一个字符,第二列 package 表示 token 是 package,第三列 “package” 表示源代码文本。我们可以看到在 Scanner 执行过程中将 \n 换行符标记成了 ; 分号,像在 C 语言中是用分号表示一行结束的。这就解释了为什么 Go 不需要分号:它们是在词法分析阶段由 Scanner 智能地解释的。语法分析源代码扫描完成后,扫描结果将被传递给语法分析器。语法分析是编译的一个阶段,它将 token 转换为 抽象语法树(AST)。 AST 是源代码的结构化表示。在 AST 中,我们将能够看到程序结构,比如函数和常量声明。我们使用 go/parser 和 go/ast 来打印完整的 AST:package mainimport ( “go/ast” “go/parser” “go/token” “log”)func main() { src := []byte(package mainimport "fmt"func main() { fmt.Println("Hello, world!")}) fset := token.NewFileSet() file, err := parser.ParseFile(fset, “”, src, 0) if err != nil { log.Fatal(err) } ast.Print(fset, file)}输出: 0 *ast.File { 1 . Package: 2:1 2 . Name: *ast.Ident { 3 . . NamePos: 2:9 4 . . Name: “main” 5 . } 6 . Decls: []ast.Decl (len = 2) { 7 . . 0: *ast.GenDecl { 8 . . . TokPos: 4:1 9 . . . Tok: import 10 . . . Lparen: - 11 . . . Specs: []ast.Spec (len = 1) { 12 . . . . 0: *ast.ImportSpec { 13 . . . . . Path: *ast.BasicLit { 14 . . . . . . ValuePos: 4:8 15 . . . . . . Kind: STRING 16 . . . . . . Value: “"fmt"” 17 . . . . . } 18 . . . . . EndPos: - 19 . . . . } 20 . . . } 21 . . . Rparen: - 22 . . } 23 . . 1: *ast.FuncDecl { 24 . . . Name: *ast.Ident { 25 . . . . NamePos: 6:6 26 . . . . Name: “main” 27 . . . . Obj: *ast.Object { 28 . . . . . Kind: func 29 . . . . . Name: “main” 30 . . . . . Decl: *(obj @ 23) 31 . . . . } 32 . . . } 33 . . . Type: *ast.FuncType { 34 . . . . Func: 6:1 35 . . . . Params: *ast.FieldList { 36 . . . . . Opening: 6:10 37 . . . . . Closing: 6:11 38 . . . . } 39 . . . } 40 . . . Body: *ast.BlockStmt { 41 . . . . Lbrace: 6:13 42 . . . . List: []ast.Stmt (len = 1) { 43 . . . . . 0: *ast.ExprStmt { 44 . . . . . . X: *ast.CallExpr { 45 . . . . . . . Fun: *ast.SelectorExpr { 46 . . . . . . . . X: *ast.Ident { 47 . . . . . . . . . NamePos: 7:2 48 . . . . . . . . . Name: “fmt” 49 . . . . . . . . } 50 . . . . . . . . Sel: *ast.Ident { 51 . . . . . . . . . NamePos: 7:6 52 . . . . . . . . . Name: “Println” 53 . . . . . . . . } 54 . . . . . . . } 55 . . . . . . . Lparen: 7:13 56 . . . . . . . Args: []ast.Expr (len = 1) { 57 . . . . . . . . 0: *ast.BasicLit { 58 . . . . . . . . . ValuePos: 7:14 59 . . . . . . . . . Kind: STRING 60 . . . . . . . . . Value: “"Hello, world!"” 61 . . . . . . . . } 62 . . . . . . . } 63 . . . . . . . Ellipsis: - 64 . . . . . . . Rparen: 7:29 65 . . . . . . } 66 . . . . . } 67 . . . . } 68 . . . . Rbrace: 8:1 69 . . . } 70 . . } 71 . } 72 . Scope: *ast.Scope { 73 . . Objects: map[string]*ast.Object (len = 1) { 74 . . . “main”: *(obj @ 27) 75 . . } 76 . } 77 . Imports: []*ast.ImportSpec (len = 1) { 78 . . 0: *(obj @ 12) 79 . } 80 . Unresolved: []*ast.Ident (len = 1) { 81 . . 0: *(obj @ 46) 82 . } 83 }分析这个输出,在 Decls 字段中,包含了代码中所有的声明,例如导入、常量、变量和函数。在本例中,我们只有两个:导入fmt包 和 主函数。为了进一步理解它,我们可以看看下面这个图,它是上述数据的表示,但只包含类型,红色代表与节点对应的代码:main函数由三个部分组成:Name、Type 和 Body。Name 是值为 main 的标识符。由 Type 字段指定的声明将包含参数列表和返回类型(如果我们指定了的话)。正文由一系列语句组成,里面包含了程序的所有行,在本例中只有一行fmt.Println(“Hello, world!")。我们的一条 fmt.Println 语句由 AST 中很多部分组成。该语句是一个 ExprStmt表达式语句(expression statement),例如,它可以像这里一样是一个函数调用,它可以是字面量,可以是一个二元运算(例如加法和减法),当然也可以是一元运算(例如自增++,自减–,否定!等)等等。同时,在函数调用的参数中可以使用任何表达式。然后,ExprStmt 又包含一个 CallExpr,它是我们实际的函数调用。里面又包括几个部分,其中最重要的部分是 Fun 和 Args。 Fun 包含对函数调用的引用,在这种情况下,它是一个 SelectorExpr,因为我们从 fmt 包中选择 Println 标识符。但是至此,在 AST 中,编译器还不知道 fmt 是一个包,它也可能是 AST 中的一个变量。Args 包含一个表达式列表,它是函数的参数。这里,我们将一个文本字符串传递给函数,因而它由一个类型为 STRING 的 BasicLit 表示。显然,AST 包含了许多信息,我们不仅可以分析出以上结论,还可以进一步检查 AST 并查找文件中的所有函数调用。下面,我们将使用 go/ast 包中的 Inspect 函数来递归地遍历树,并分析所有节点的信息。package mainimport ( “fmt” “go/ast” “go/parser” “go/printer” “go/token” “os”)func main() { src := []byte(package mainimport "fmt"func main() { fmt.Println("Hello, world!")}) fset := token.NewFileSet() file, err := parser.ParseFile(fset, “”, src, 0) if err != nil { fmt.Println(err) } ast.Inspect(file, func(n ast.Node) bool { call, ok := n.(ast.CallExpr) if !ok { return true } printer.Fprint(os.Stdout, fset, call.Fun) return false })}输出:fmt.Println上面代码的作用是查找所有节点以及它们是否为 ast.CallExpr 类型,上面也说过这种类型是函数调用。如果是,则使用 go/printer 包打印 Fun 中存在的函数的名称。构建出 AST 后,将使用 GOPATH 或者在 Go 1.11 及更高版本中的 modules 解析所有导入。然后,执行类型检查,并做一些让程序运行更快的初级优化。代码生成在解析导入并做了类型检查之后,我们可以确认程序是合法的 Go 代码,然后就走到将 AST 转换为(伪)目标机器码的过程。此过程的第一步是将 AST 转换为程序的低级表示,特别是转换为 静态单赋值(SSA)表单。这个中间表示不是最终的机器代码,但它确实代表了最终的机器代码。 SSA 具有一组属性,会使应用优化变得更容易,其中最重要的是在使用变量之前总是定义变量,并且每个变量只分配一次。在生成 SSA 的初始版本之后,将执行一些优化。这些优化适用于某些代码,可以使处理器执行起来更简单且更快速。例如,可以做 死码消除。还有比如可以删除某些 nil 检查,因为编译器可以证明这些检查永远不会出错。现在通过最简单的例子来说明 SSA 和一些优化过程:package mainimport “fmt"func main() { fmt.Println(2)}如你所见,此程序只有一个函数和一个导入。它会在运行时打印 2。但是,此例足以让我们了解SSA。为了显示生成的 SSA,我们需要将 GOSSAFUNC 环境变量设置为我们想要跟踪的函数,在本例中为main 函数。我们还需要将 -S 标识传递给编译器,这样它就会打印代码并创建一个HTML文件。我们还将编译Linux 64位的文件,以确保机器代码与您在这里看到的相同。在终端执行下面的命令:GOSSAFUNC=main GOOS=linux GOARCH=amd64 go build -gcflags -S main.go会在终端打印出所有的 SSA,同时也会生成一个交互式的 ssa.html 文件,我们用浏览器打开它。当你打开 ssa.html 时,将显示很多阶段,其中大部分都已折叠。start 阶段是从 AST 生成的SSA;lower 阶段将非机器特定的 SSA 转换为机器特定的 SSA,最后的 genssa 就是生成的机器代码。start 阶段的代码如下:b1: v1 = InitMem <mem> v2 = SP <uintptr> v3 = SB <uintptr> v4 = ConstInterface <interface {}> v5 = ArrayMake1 <[1]interface {}> v4 v6 = VarDef <mem> {.autotmp_0} v1 v7 = LocalAddr <[1]interface {}> {.autotmp_0} v2 v6 v8 = Store <mem> {[1]interface {}} v7 v5 v6 v9 = LocalAddr <[1]interface {}> {.autotmp_0} v2 v8 v10 = Addr <*uint8> {type.int} v3 v11 = Addr <*int> {”".statictmp_0} v3 v12 = IMake <interface {}> v10 v11 v13 = NilCheck <void> v9 v8 v14 = Const64 <int> [0] v15 = Const64 <int> [1] v16 = PtrIndex <interface {}> v9 v14 v17 = Store <mem> {interface {}} v16 v12 v8 v18 = NilCheck <void> v9 v17 v19 = IsSliceInBounds <bool> v14 v15 v24 = OffPtr <[]interface {}> [0] v2 v28 = OffPtr <*int> [24] v2If v19 → b2 b3 (likely) (line 6)b2: ← b1 v22 = Sub64 <int> v15 v14 v23 = SliceMake <[]interface {}> v9 v22 v22 v25 = Copy <mem> v17 v26 = Store <mem> {[]interface {}} v24 v23 v25 v27 = StaticCall <mem> {fmt.Println} [48] v26 v29 = VarKill <mem> {.autotmp_0} v27Ret v29 (line 7)b3: ← b1 v20 = Copy <mem> v17 v21 = StaticCall <mem> {runtime.panicslice} v20Exit v21 (line 6)这个简单的程序就已经产生了相当多的 SSA(总共35行)。然而,很多都是引用,可以消除很多(最终的SSA版本有28行,最终的机器代码版本有18行)。每个 v 都是一个新变量,可以点击来查看它被使用的位置。b 是块,这里有三块:b1,b2,b3。b1 始终会执行,b2 和 b3 是条件块,满足条件才执行。我们来看 b1 结尾处的 If v19 → b2 b3 (likely)。单击该行中的 v19 可以查看它定义的位置。可以看到它定义为 IsSliceInBounds <bool> v14 v15,通过 Go 编译器源代码,我们知道 IsSliceInBounds 的作用是检查 0 <= arg0 <= arg1。然后单击 v14 和 v15 看看在哪定义的,我们会看到 v14 = Const64 <int> [0],Const64 是一个常量 64 位整数。 v15 定义一样,放在 args1 的位置。所以,实际执行的是 0 <= 0 <= 1,这显然是正确的。编译器也能够证明这一点,当我们查看 opt 阶段(“机器无关优化”)时,我们可以看到它已经重写了 v19 为 ConstBool <bool> [true]。结果就是,在 opt deadcode 阶段,b3 条件块被删除了,因为永远也不会执行到 b3。下面来看一下 Go 编译器在把 SSA 转换为 机器特定的SSA 之后所做的另一个更简单的优化,基于amd64体系结构的机器代码。下面,我们将比较 lower 和 lowered deadcode。lower:b1: BlockInvalid (6)b2: v2 (?) = SP <uintptr> v3 (?) = SB <uintptr> v10 (?) = LEAQ <*uint8> {type.int} v3 v11 (?) = LEAQ <int> {”".statictmp_0} v3 v15 (?) = MOVQconst <int> [1] v20 (?) = MOVQconst <uintptr> [0] v25 (?) = MOVQconst <uint8> [0] v1 (?) = InitMem <mem> v6 (6) = VarDef <mem> {.autotmp_0} v1 v7 (6) = LEAQ <[1]interface {}> {.autotmp_0} v2 v9 (6) = LEAQ <[1]interface {}> {.autotmp_0} v2 v16 (+6) = LEAQ <*interface {}> {.autotmp_0} v2 v18 (6) = LEAQ <**uint8> {.autotmp_0} [8] v2 v21 (6) = LEAQ <**uint8> {.autotmp_0} [8] v2 v30 (6) = LEAQ <*int> [16] v2 v19 (6) = LEAQ <*int> [8] v2 v23 (6) = MOVOconst <int128> [0] v8 (6) = MOVOstore <mem> {.autotmp_0} v2 v23 v6 v22 (6) = MOVQstore <mem> {.autotmp_0} v2 v10 v8 v17 (6) = MOVQstore <mem> {.autotmp_0} [8] v2 v11 v22 v14 (6) = MOVQstore <mem> v2 v9 v17 v28 (6) = MOVQstoreconst <mem> [val=1,off=8] v2 v14 v26 (6) = MOVQstoreconst <mem> [val=1,off=16] v2 v28 v27 (6) = CALLstatic <mem> {fmt.Println} [48] v26 v29 (5) = VarKill <mem> {.autotmp_0} v27Ret v29 (+7)在HTML中,某些行是灰色的,这意味着它们将在下一个阶段中被删除或修改。例如,v15 (?) = MOVQconst <int> [1] 显示为灰色。点击 v15,我们看到它在其他地方都没有使用,而 MOVQconst 基本上与我们之前看到的 Const64 相同,只针对amd64的特定机器。我们把 v15 设置为1。但是,v15 在其他地方都没有使用,所以它是无用的(死的)代码并且可以消除。Go 编译器应用了很多这类优化。因此,虽然 AST 生成的初始 SSA 可能不是最快的实现,但编译器将SSA优化为更快的版本。 HTML 文件中的每个阶段都有可能发生优化。如果你有兴趣了解 Go 编译器中有关 SSA 的更多信息,请查看 Go 编译器的 SSA 源代码。这里定义了所有的操作以及优化。结论Go 是一种非常高效且高性能的语言,由其编译器及其优化支撑。要了解有关 Go 编译器的更多信息,源代码的 README 是不错的选择。 ...

September 27, 2018 · 8 min · jiezi

idea中报Error:java: Compilation failed: internal java compiler error

set中java complier 设置的问题 ,项目中有人用jdk1.6 有人用jdk1.7 版本不一样 会一起这个错误进行如下操作:

February 7, 2018 · 1 min · jiezi