当前位置: 首页 > 编程日记 > 正文

Scons构建C++项目

旧博文,搬到 csdn
原文:http://rebootcat.com/2020/08/30/scons/

前言

我是一个 linux c++ 开发者,但是一直对 Makefile 的语法很是头痛,每次都记不住,所以每次写 Makefile 都很痛苦,Makefile 里需要你自己编写依赖和推导规则,这个过程能不能简单点呢?

对于编译一个 C++ 工程来说,也许需要的就是头文件路径、库路径、编译参数,剩下的东西基本也不重要,这三样足够去编译一个工程了。所以有没有一个工具能简单点的去实现 C++ 项目的构建呢?

答案是有的,Scons 就是答案。

Scons

什么是 scons

这里直接引用官网的解释:

What is SCons?

SCons is an Open Source software construction tool—that is, a next-generation build tool. Think of SCons as an improved, cross-platform substitute for the classic Make utility with integrated functionality similar to autoconf/automake and compiler caches such as ccache. In short, SCons is an easier, more reliable and faster way to build software.

What makes SCons better?

  • Configuration files are Python scripts–use the power of a real programming language to solve build problems.
  • Reliable, automatic dependency analysis built-in for C, C++ and Fortran–no more “make depend” or “make clean” to get all of the dependencies. Dependency analysis is easily extensible through user-defined dependency Scanners for other languages or file types.
  • Built-in support for C, C++, D, Java, Fortran, Yacc, Lex, Qt and SWIG, and building TeX and LaTeX documents. Easily extensible through user-defined Builders for other languages or file types.
  • Building from central repositories of source code and/or pre-built targets.
  • Built-in support for fetching source files from SCCS, RCS, CVS, BitKeeper and Perforce.
  • Built-in support for Microsoft Visual Studio .NET and past Visual Studio versions, including generation of .dsp, .dsw, .sln and .vcproj files.
  • Reliable detection of build changes using MD5 signatures; optional, configurable support for traditional timestamps.
  • Improved support for parallel builds–like make -j but keeps N jobs running simultaneously regardless of directory hierarchy.
  • Integrated Autoconf-like support for finding #include files, libraries, functions and typedefs.
  • Global view of all dependencies–no more multiple build passes or reordering targets to build everything.
  • Ability to share built files in a cache to speed up multiple builds–like ccache but for any type of target file, not just C/C++ compilation.
  • Designed from the ground up for cross-platform builds, and known to work on Linux, other POSIX systems (including AIX, BSD systems, HP/UX, IRIX and Solaris), Windows NT, Mac OS X, and OS/2.

最大特点就是使用 Python 语法来编写编译构建脚本,并且支持依赖自动推导,支持编译 C/C++/D/Java/Fortran等项目,并且是跨平台的(因为 python 是跨平台的)。

所以如果你对 python 熟悉的话,而且你和我对 C++ Makefile 有一样的烦恼,那么这对你将是一个好消息。 你将可以用 python 来编写构建脚本,而且会很简单,对于复杂的大型项目也能快速构建好。(也许只要 30 分钟)

安装 scons

因为 scons 是基于 python 来构建的,所以毋容置疑,首先是需要准备好 python 环境,然后使用下述命令安装 scons 工具。

pip install scons

scons 使用语法

注:本文以一个多源文件,多目录结构的项目 mux 为例,介绍 cmake 的使用,相关源文件以及cmake 脚本可以直接查看源项目

scons 构建脚本由一个 SConstruct 文件和多个 SConscript 文件构成。

SConstruct 通常位于项目顶层目录,然后 SConscript 通常位于子目录(子模块)。

那么来看一下 SConstruct 脚本长啥样?

SConstruct

#!/usr/bin/env python
#-*- coding:utf-8 -*-import sys
import os
import platform
import reenv = Environment()
abs_path = os.getcwd()
print('workspace path:{0}'.format(abs_path))sbuild_dir = 'sbuild'headers = ['.', 'third-party/include']
libs = ['./third-party/lib']abs_headers = []
abs_libs = []for item in headers:abs_item = os.path.join(abs_path, item)abs_headers.append(abs_item)for item in libs:abs_item = os.path.join(abs_path, item)abs_libs.append(abs_item)build_dir = os.path.join(abs_path, sbuild_dir)
abs_libs.append(os.path.join(build_dir, 'lib'))CCFLAGS = '-ggdb -std=c++11'print('\nheaders path:')
print(abs_headers)
print('\n')print('libs path:')
print(abs_libs)
print('\n')print("begin load SConscript")env["headers"] = abs_headers
env["libs"]    = abs_libs
env["MUX_DIR"] = abs_path
env['ccflags'] = CCFLAGS
env['build_dir'] = build_dirExport('env')SConscript(['./mbase/SConscript'])
SConscript(['./message_handle/SConscript'])
SConscript(['./epoll/SConscript'])
SConscript(['./transport/SConscript'])
SConscript(['./demo/bench/SConscript'])
SConscript(['./demo/echo/SConscript'])print("\n All Done, Please Check {0}".format(env['build_dir']))

来分析一下这个文件,源文件可以直接在 我的github下载。

SConstruct 文件主要做了两件事:

  • env 环境变量的构造,主要是头文件路径,库路径,编译参数,自定义的一些变量等
  • 使用 SConscript 函数解析执行子模块的 SConscript 文件

需要注意的是 SConstruct 和 SConscript 共享变量使用的就是 env 这个变量,你可以看到上面有一句:

Export('env')

这句很重要。

SConscript

那么位于子模块或者子目录的 SConscript 文件长啥样呢?

#!/usr/bin/env python
#-*- coding:utf-8 -*-import os
import sysImport('env')
project_dir  = env['MUX_DIR']epoll_lib  = 'epoll'epoll_src_path = os.path.join(project_dir, 'epoll/src')
epoll_sources = []
for item in os.listdir(epoll_src_path):if item.endswith('.cc') or item.endswith('.cpp') or item.endswith('.cxx'):abs_item = os.path.join(epoll_src_path, item)epoll_sources.append(abs_item)print('\nbuild target:lib{0}.a'.format(epoll_lib))
print(epoll_sources)lib_dir = os.path.join(env['build_dir'], 'lib')link_libraries = ['mbase']
for lib_name in link_libraries:lib_name = "{0}{1}{2}".format(env['LIBPREFIX'], lib_name, env['LIBSUFFIX'])abs_lib_name = os.path.join(lib_dir, lib_name)epoll_sources.append(abs_lib_name)env.StaticLibrary(target = os.path.join(lib_dir, epoll_lib),source  = epoll_sources,CPPPATH = env['headers'], # includeLIBPATH = env['libs'],    # lib pathLIBS    = ['pthread'],    # link libCCFLAGS = env['ccflags'])

来分析一下这个文件,源文件可以直接在 我的github下载。

SConscript 主要做了两件事:

  • 构造一个源文件列表(用来构建 target 所需要使用的源文件)
  • 根据需要构建 static_lib/dynamic_lib/binary

当然,还有一点很重要,上面其实提到了,SConscript 和 SConstruct 用来共享变量使用的是 env 这个变量,所以你可以看到一句很重要的:

Import('env')

构造源文件列表,对于 Python 来说,简直是小菜一碟,太简单了;

然后如何生成目标文件呢?

1 生成二进制文件

env.Program(target = os.path.join(bin_dir, echo_server_bin),source  = echo_server_sources,CPPPATH = env['headers'],LIBPATH = env['libs'],LIBS    = ['transport','msghandler','epoll', 'mbase', 'pthread'],CCFLAGS = env['ccflags'])

2 生成静态库

env.StaticLibrary(target = os.path.join(lib_dir, epoll_lib),source  = epoll_sources,CPPPATH = env['headers'], # includeLIBPATH = env['libs'],    # lib pathLIBS    = ['pthread'],    # link libCCFLAGS = env['ccflags'])

3 生成动态库

env.SharedLibrary(target = os.path.join(lib_dir, epoll_lib),source  = epoll_sources,CPPPATH = env['headers'], # includeLIBPATH = env['libs'],    # lib pathLIBS    = ['pthread'],    # link libCCFLAGS = env['ccflags'])

上面 3 个函数的参数都是类似的:

  • target: 指定需要生成的目标文件,通常我自己会写一个绝对路径;对于 lib 来说只需要写名字就行,前缀和后缀不需要写。(eg. target = ‘/root/scons_repo/sbuild/lib/test’ ,会生成 /root/scons_repo/sbuild/lib/libtest.a)
  • source: 编译目标文件需要的源文件列表
  • CPPPATH: 通常就是需要 Include 的头文件路径
  • LIBPATH: 通常就是需要链接的库路径
  • LIBS: 需要链接的库列表
  • CCFLAGS: 编译参数

attention:

上面有一个坑我自己碰到的,当我构建目标生成一个静态库的时候,需要链接其他的静态库,如果使用 $LIBPATH 和 $LIBS 指定链接库的话,scons 并没有链接这些库。尝试了很多方法,搜索了很多,也没有解决这个问题

最后是这样解决的。把需要链接的静态库添加到 source 参数中,和其他 cc/cpp 源文件一样放在一起,并且这些库需要使用绝对路径

通常为了跨平台的方便,需要考虑lib 的前后缀,可以这样写:

link_libraries = ['test1', 'test2']
for lib_name in link_libraries:lib_name = "{0}{1}{2}".format(env['LIBPREFIX'], lib_name, env['LIBSUFFIX'])abs_lib_name = os.path.join(lib_dir, lib_name)sources.append(abs_lib_name)

scons 命令

上面详细讲解了如何使用 python 编写构建脚本,那么写好之后怎么用呢?

常用的几个命令:

编译

scons

如果需要并行编译:

scons -j4

清理

scons -c

然后就会按照你脚本里写的方式去构建目标了。

这里贴一下 我的项目 编译的输出:

$ scons
scons: Reading SConscript files ...
workspace path:/mnt/centos-share/workspace/muxheaders path:
['/mnt/centos-share/workspace/mux/.', '/mnt/centos-share/workspace/mux/third-party/include']libs path:
['/mnt/centos-share/workspace/mux/./third-party/lib', '/mnt/centos-share/workspace/mux/sbuild/lib']begin load SConscriptbuild target:libmbase.a
['/mnt/centos-share/workspace/mux/mbase/src/packet.cc']build target:libmsghandler.a
['/mnt/centos-share/workspace/mux/message_handle/src/message_handler.cc']build target:libepoll.a
['/mnt/centos-share/workspace/mux/epoll/src/epoll_tcp_client.cc', '/mnt/centos-share/workspace/mux/epoll/src/epoll_tcp_server.cc']build target:libtransport.a
['/mnt/centos-share/workspace/mux/transport/src/tcp_transport.cc']build target:bench_server
['bench_server.cc']build target:bench_client
['client.cc']build target:echo_server
['echo_server.cc']build target:echo_client
['client.cc']All Done, Please Check /mnt/centos-share/workspace/mux/sbuild
scons: done reading SConscript files.
scons: Building targets ...
g++ -o demo/bench/bench_server.o -c -ggdb -std=c++11 -I. -Ithird-party/include demo/bench/bench_server.cc
g++ -o demo/bench/client.o -c -ggdb -std=c++11 -I. -Ithird-party/include demo/bench/client.cc
g++ -o demo/echo/client.o -c -ggdb -std=c++11 -I. -Ithird-party/include demo/echo/client.cc
g++ -o demo/echo/echo_server.o -c -ggdb -std=c++11 -I. -Ithird-party/include demo/echo/echo_server.cc
g++ -o epoll/src/epoll_tcp_client.o -c -ggdb -std=c++11 -I. -Ithird-party/include epoll/src/epoll_tcp_client.cc
g++ -o epoll/src/epoll_tcp_server.o -c -ggdb -std=c++11 -I. -Ithird-party/include epoll/src/epoll_tcp_server.cc
g++ -o mbase/src/packet.o -c -ggdb -std=c++11 -I. -Ithird-party/include mbase/src/packet.cc
g++ -o message_handle/src/message_handler.o -c -ggdb -std=c++11 -I. -Ithird-party/include message_handle/src/message_handler.cc
g++ -o transport/src/tcp_transport.o -c -ggdb -std=c++11 -I. -Ithird-party/include transport/src/tcp_transport.cc
ar rc sbuild/lib/libmbase.a mbase/src/packet.o
ranlib sbuild/lib/libmbase.a
ar rc sbuild/lib/libepoll.a epoll/src/epoll_tcp_client.o epoll/src/epoll_tcp_server.o sbuild/lib/libmbase.a
ranlib sbuild/lib/libepoll.a
ar rc sbuild/lib/libtransport.a transport/src/tcp_transport.o sbuild/lib/libepoll.a sbuild/lib/libmbase.a
ranlib sbuild/lib/libtransport.a
ar rc sbuild/lib/libmsghandler.a message_handle/src/message_handler.o sbuild/lib/libmbase.a
ranlib sbuild/lib/libmsghandler.a
g++ -o sbuild/bin/bench_client demo/bench/client.o -Lthird-party/lib -Lsbuild/lib -ltransport -lmsghandler -lepoll -lmbase -lpthread
g++ -o sbuild/bin/bench_server demo/bench/bench_server.o -Lthird-party/lib -Lsbuild/lib -ltransport -lmsghandler -lepoll -lmbase -lpthread
g++ -o sbuild/bin/echo_client demo/echo/client.o -Lthird-party/lib -Lsbuild/lib -ltransport -lmsghandler -lepoll -lmbase -lpthread
g++ -o sbuild/bin/echo_server demo/echo/echo_server.o -Lthird-party/lib -Lsbuild/lib -ltransport -lmsghandler -lepoll -lmbase -lpthread
scons: done building targets.
$ scons -c
scons: Reading SConscript files ...
workspace path:/mnt/centos-share/workspace/muxheaders path:
['/mnt/centos-share/workspace/mux/.', '/mnt/centos-share/workspace/mux/third-party/include']libs path:
['/mnt/centos-share/workspace/mux/./third-party/lib', '/mnt/centos-share/workspace/mux/sbuild/lib']begin load SConscriptbuild target:libmbase.a
['/mnt/centos-share/workspace/mux/mbase/src/packet.cc']build target:libmsghandler.a
['/mnt/centos-share/workspace/mux/message_handle/src/message_handler.cc']build target:libepoll.a
['/mnt/centos-share/workspace/mux/epoll/src/epoll_tcp_client.cc', '/mnt/centos-share/workspace/mux/epoll/src/epoll_tcp_server.cc']build target:libtransport.a
['/mnt/centos-share/workspace/mux/transport/src/tcp_transport.cc']build target:bench_server
['bench_server.cc']build target:bench_client
['client.cc']build target:echo_server
['echo_server.cc']build target:echo_client
['client.cc']All Done, Please Check /mnt/centos-share/workspace/mux/sbuild
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed demo/bench/bench_server.o
Removed demo/bench/client.o
Removed demo/echo/client.o
Removed demo/echo/echo_server.o
Removed epoll/src/epoll_tcp_client.o
Removed epoll/src/epoll_tcp_server.o
Removed mbase/src/packet.o
Removed message_handle/src/message_handler.o
Removed transport/src/tcp_transport.o
Removed sbuild/lib/libmbase.a
Removed sbuild/lib/libepoll.a
Removed sbuild/lib/libtransport.a
Removed sbuild/lib/libmsghandler.a
Removed sbuild/bin/bench_client
Removed sbuild/bin/bench_server
Removed sbuild/bin/echo_client
Removed sbuild/bin/echo_server
scons: done cleaning targets.

写在最后

scons 使用 python 脚本来构建项目,如果对 python 熟悉的话,那么编写编译构建脚本将会大大提高效率,再也不用局限在 Makefile 的蛋疼语法里面了。

当然 scons 的缺点也有,据说在大型项目的时候,可能会很慢。这个我还没碰到过,因为没有用到大型项目中。

下一篇,分享下 cmake 构建 C++ 项目的一些语法和步骤。

cmake教程|cmake入门实战

另外,文中涉及到的项目可以在我的github 找到。

Blog:

  • rebootcat.com

  • email: linuxcode2niki@gmail.com

2020-08-30 于杭州
By 史矛革

相关文章:

2020 AI产业图谱启动,勾勒中国AI技术与行业生态

《2020年国务院政府工作报告》提出,重点支持「两新一重」建设。其中「两新一重」中的第一个「新」,就是新基建,而人工智能是新基建的重要组成部分。新基建首次被纳入政府工作报告后,各大科技厂商纷纷押注,重金投向「新…

Windows Phone 7 SDK 7.1 Beta2 发布

早上看到消息,有Marketplace账号的筒子们注意了,可以去下载芒果的ROM了,一个开发者账号只能更新一个WP7,以下是App hub上的消息:来自http://create.msdn.com/en-US/news/Mango_Beta。关于开发工具的更新,可…

javascript基础语法——表达式

前面的话 一般地,关于javascript基础语法,人们听得比较多的术语是操作符和语句。但是,其实还有一个术语经常使用,却很少被提到,这就是javascript表达式(expression)。本文将详细介绍javascript表达式,表达式…

Hexo Next 博客添加相册瀑布流

原文:https://rebootcat.com/2020/09/19/nextphotowall/ 前言 一直没有时间来整理下博客搭建的一些事情,现在补上一篇,给 Hexo Next 博客添加一个相册功能,使用瀑布流的方式。 原理说明 使用 github 作为仓库存储图片文件&…

【分享几个日常巡检 监控数据库的语句】

查看数据库表空间语句 select df.tablespace_name "表空间名",totalspace "总空间M",freespace "剩余空间M",round((1-freespace/totalspace)*100,2) "使用率%" from (select tablespace_name,round(sum(bytes)/1024/1024) totalspa…

AI换脸、声音篡改等,明确写入新版《民法典》

来源 | HyperAI超神经5 月 28 日,十三届全国人大三次会议表决通过了《中华人民共和国民法典》(以下简称《民法典》)第四编人格权中的第四章肖像权,明确提出了以信息技术手段,对于他人肖像、声音等权益的侵害认定。《民…

awk: (FILENAME=- FNR=1) 致命错误: 试图访问字段 -2

执行:awk {print $(NF-2)} aa.log出现错误:awk: (FILENAMEaa.log FNR1) 致命错误: 试图访问字段 -2可能和aa.log中数据有关系:改为:awk NF>1{print $(NF-2)} aa.log转载于:https://blog.51cto.com/henly/1786692

迁移博客到香港虚拟空间

原文: https://rebootcat.com/2020/09/20/virtual_space_blog/ 缘起 我的博客一直采用的是 github pages 来托管,中间断断续续的也没怎么管理过,偶尔写几篇博客,所以也就没怎么关心过访问速度,搜索引擎收录等问题。 …

自动化神经网络理论进展缓慢,AutoML算法的边界到底在哪?

作者 | 夕颜出品 | CSDN(ID:CSDNnews)「AI 技术生态论」 人物访谈栏目是 CSDN 发起的百万人学 AI 倡议下的重要组成部分。通过对 AI 生态顶级大咖、创业者、行业 KOL 的访谈,反映其对于行业的思考、未来趋势判断、技术实践,以及成…

让电脑通过gns3里的路由器上网

题目我感觉写的不好,反正就是这个意思,看下文 头几天有网友问cisco2811路由器怎么用ACL封掉QQ,当时就想帮他,但是手里又没有cisco路由器,只有GNS3 cisco模拟器。 现在的问题就是要用gns3模拟器的路由器充当真实工作中的…

文件上传的渐进式增强

文件上传是最古老的互联网操作之一。 20多年了,它几乎没变,还是原来的样子:操作麻烦、缺乏交互、用户体验不佳。在这个新技术日新月异的时代,显得非常落伍。 网页开发者们想了很多办法,试图提升文件上传的功能和操作体…

使用 mkdocs 搭建个人 wiki 站点

原文: https://rebootcat.com/2020/09/20/wiki/ why wiki 博客通常是用来记录一些完整的文章,每篇文章有一个主题。但是我想把平日里的一些笔记也记录到我的博客里,但笔记是零散的,随时的,不是完整的一个主题。所以打…

追忆童年,教你用Python画出儿时卡通人物

作者 | 张同学来源 | 凹凸数据大家好,我是张同学。又到一年一度的国际儿童节,作为逢节必过的程序猿,怎么可以放过这个学习技能的机会呢?于是,今天我们来学习 Python 的 Turtle 库绘制童年的卡通人物,一起做…

xx学OD -- 消息断点 RUN跟踪(上)

这一篇讲的是 消息断点和RUN跟踪的简单知识这一篇没怎么看明白 大概使用知道了 怎么用不太清楚。介绍本次软件特点输入后木有反应(纱布垃圾的。。哈哈)启动OllyDBG载入这个程序,F9让它运行。这个程序按我们前面讲的采用字串参考或函数参考的方法都很容易断下来。…

iOS-UIWebView添加头部和尾部

2019独角兽企业重金招聘Python工程师标准>>> 前言 项目中使用UIWebView显示本地或者是服务器上的页面很容易,但是仅限于显示页面,可控性并不高,如果有需要在头部和尾部加上原生的view,显示部分信息相对于全部使用UIWeb…

epoll 入门例子 tcp server/client

原文: https://rebootcat.com/2020/09/26/epoll_examples/ 复习一下 上一篇博文 epoll原理深入分析 详细分析了 epoll 底层的实现原理,如果对 epoll 原理有模糊的建议先看一下这篇文章。那么本文就开始用 epoll 实现一个简单的 tcp server/client。 本…

张红忠:智慧化时代,如何通吃5G模组、AIoT?

受访者 | 张红忠,日海智能副总裁、云AIoT创新中心总经理记者 | Aholiab,编辑 | 邓晓娟出品 | AI科技大本营(ID:rgznai100)日海智能是目前国内AIoT领域的头部企业,以AIoT为核心,形成了5G&AI物联网终端、…

JQUERY打造隐藏在左侧的弹性弹出菜单

代码简介: 隐藏在左侧的弹性弹出菜单,从淘宝扣下来的,也可作为JAvaScript缓冲动画的典型教程。本弹性菜单可扩展性强,实际上不光可以做成菜单,也可布局一些图文混排的内容或一段视频,总之被弹出的内容是在一…

Num55 boss09(activiti安装以及API)

2019独角兽企业重金招聘Python工程师标准>>> 安装流程设计器插件: 使用框架提供的方式创建23张表: 流程部署,定义,启动&查询,办理任务: 流程的部署,查询,删除 & …

模仿nginx修改进程名

个人博客原文: https://rebootcat.com/2020/10/25/setproctitle/ nginx 进程名 使用 nginx 的过程中,我们经常看到 nginx 的进程名是不同的,如下: $ ps -ef |grep nginx smaug 1183 1115 0 05:46 pts/2 00:00:00 grep …

机器学习模型的超参数优化 | 原力计划

作者 | deephub责编 | 王晓曼出品 | CSDN博客头图 | CSDN付费下载自东方IC引言模型优化是机器学习算法实现中最困难的挑战之一。机器学习和深度学习理论的所有分支都致力于模型的优化。机器学习中的超参数优化旨在寻找使得机器学习算法在验证数据集上表现性能最佳的超参数。超参…

准备IE--复习NP,NP从头开始,每天学一点,就多一点收获

2011-07-07 今天开始重新开始NP!每天一实验,加油!写下心路历程,为自己加油!转载于:https://blog.51cto.com/sunchangsheng/605482

[20160608]自治事务引起死锁.txt

[20160608]自治事务引起死锁.txt --链接http://www.itpub.net/thread-2060966-2-1.html上的讨论,很久以前也遇到过 --(http://blog.itpub.net/267265/viewspace-721262/),时间有点久远,自己重复测试看看: 1.环境: SCOTTtest> &r/ver1 PORT_STRING V…

动感效果的TAB选项卡 jquery 插件

动感效果的TAB选项卡 jquery 插件 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns"http://www.w3.org/1999/xhtml"><head><me…

Linux上隐藏进程名(初级版)

缘起 上一篇博文 模仿nginx修改进程名 中提到了一种修改进程名的方法&#xff0c;就像 nginx 一样&#xff0c;给不同进程命名为 master 以及 worker 等。那么能不能把新进程名设置为空字符串呢&#xff1f;如果能&#xff0c;又会有哪些应用场景呢&#xff1f; 答案可能是能…

神操作!一行Python代码搞定一款游戏?给力!

来源&#xff1a;pypl编程榜一直以来Python长期霸占编程语言排行榜前三位&#xff0c;其简洁&#xff0c;功能强大的特性使越来越多的小伙伴开始学习Python 。甚至K12的同学都开始学习Python 编程。新手入门的时候趣味性其实最重要的。那么一行Python 代码到底能玩出什么花样&a…

jquery对所有input type=text的控件赋值

function resetData() { $("input[typetext]").each( function() { $(this).attr("value",""); } ); }

free not return memory

个人博客&#xff1a;https://rebootcat.com/2020/11/05/free_mem/ 内存泄露&#xff1f; 观察到一台机器上的内存使用量在程序启动之后&#xff0c;持续增长&#xff0c;中间没有出现内存恢复。怀疑是不是出现了内存泄露的问题&#xff1f; 然后使用相关的内存分析工具进行了…

成大事必备9种能力

挑战生存的能力&#xff1a;善于在现实中寻找答案 1、摆正心态&#xff0c;敢于面对现实 对于那些不停地抱怨现实恶劣的人来说&#xff0c;不能称心如意的现实&#xff0c;就如同生活的牢笼&a…

懂语言者得天下:NLP凭什么被称为人工智能的掌上明珠?

受访者 | 简仁贤&#xff0c;竹间智能创始人&CEO记者 | 邓晓娟出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;随着技术的发展&#xff0c;大数据、云计算、人工智能、区块链都慢慢地为人熟知。2016 年 Google 推出 AlphaGo&#xff0c;让人工智能走进了大众的视…