交叉编译Python-2.7.13到ARM(aarch32)—— 支持sqlite3
作者:彭东林
邮箱:pengdonglin137@163.com
QQ: 405728433
环境
主机: ubuntu14.04 64bit
开发板: qemu + vexpress-a9 (参考: http://www.cnblogs.com/pengdonglin137/p/6442583.html)
工具链: arm-none-linux-gnueabi-gcc (gcc version 4.8.3 20140320)
Python版本: Python-2.7.13
概述
前面一篇博文(交叉编译Python-2.7.13到ARM(aarch32)平台)介绍了移植python到aarch32上面,但是发现有很多模块都不能用,可以在板子上面执行下面的命令测试一下:
[root@vexpress ]# python /usr/lib/python2.7/test/test___all__.py
Traceback (most recent call last):
File "/usr/lib/python2.7/test/test___all__.py", line 3, in <module>
import unittest
File "/usr/lib/python2.7/unittest/__init__.py", line 58, in <module>
from .result import TestResult
File "/usr/lib/python2.7/unittest/result.py", line 9, in <module>
from . import util
File "/usr/lib/python2.7/unittest/util.py", line 2, in <module>
from collections import namedtuple, OrderedDict
File "/usr/lib/python2.7/collections.py", line 20, in <module>
from _collections import deque, defaultdict
ImportError: No module named _collections
可以看到这里找不到_collections模块。
对比x86_64的编译结果:
ls x86_64/build/lib.linux-x86_64-2.7/
array.so* _codecs_hk.so* cPickle.so* _curses_panel.so* future_builtins.so* itertools.so* mmap.so* parser.so* _socket.so* _sysconfigdata.py time.so*
audioop.so* _codecs_iso2022.so* crypt.so* _curses.so* grp.so* _json.so* _multibytecodec.so* pyexpat.so* spwd.so* _sysconfigdata.pyc unicodedata.so*
binascii.so* _codecs_jp.so* cStringIO.so* datetime.so* _hashlib.so* linuxaudiodev.so* _multiprocessing.so* _random.so* _sqlite3.so* _sysconfigdata.pyo zlib.so*
_bisect.so* _codecs_kr.so* _csv.so* _elementtree.so* _heapq.so* _locale.so* nis.so* readline.so* _ssl.so* syslog.so*
cmath.so* _codecs_tw.so* _ctypes.so* fcntl.so* _hotshot.so* _lsprof.so* operator.so* resource.so* strop.so* termios.so*
_codecs_cn.so* _collections.so* _ctypes_test.so* _functools.so* _io.so* math.so* ossaudiodev.so* select.so* _struct.so* _testcapi.so*
而aarch32的编译结果:
$ls aarch32/build/lib.linux2-arm-2.7/
audioop.so* _codecs_iso2022.so* _codecs_tw.so* _ctypes.so* _elementtree.so* _json.so* mmap.so* nis.so* resource.so* termios.so*
_codecs_cn.so* _codecs_jp.so* crypt.so* _ctypes_test.so* future_builtins.so* linuxaudiodev.so* _multibytecodec.so* parser.so* _sysconfigdata.py _testcapi.so*
_codecs_hk.so* _codecs_kr.so* _csv.so* datetime.so* _hotshot.so* _lsprof.so* _multiprocessing.so* pyexpat.so* _sysconfigdata.pyc
可以看到,aarch32上面缺少了很多库, 比如_collections.so,将来这些库会被安装到/usr/lib/python2.7/lib-dynload下面, 所以下面要说的就是将缺少的这些库弄回来!
正文
1、通过分析setup.py发现问题
在函数build_extensions中刚开始self.extensions中存放的是需要编译库, 通过在加打印:
diff --git a/setup.py b/setup.py
index 54054c2..bc16bb1
--- a/setup.py
+++ b/setup.py
@@ -, +, @@ class PyBuildExt(build_ext): def build_extensions(self): + print "build_extensions enter."
# Detect which modules should be compiled
missing = self.detect_modules() @@ -, +, @@ class PyBuildExt(build_ext):
extensions.append(ctypes)
self.extensions = extensions + for ext in self.extensions:
+ print "extensions: ", ext.name
+
# Fix up the autodetected modules, prefixing all the source files
# with Modules/ and adding Python's include directory to the path.
(srcdir,) = sysconfig.get_config_vars('srcdir')
@@ -, +, @@ class PyBuildExt(build_ext):
# Python header files
headers = [sysconfig.get_config_h_filename()]
headers += glob(os.path.join(sysconfig.get_path('include'), "*.h"))
+
+ print "builtin_module_names: ", sys.builtin_module_names
for ext in self.extensions[:]:
ext.sources = [ find_module_file(filename, moddirlist)
for filename in ext.sources ]
@@ -, +, @@ class PyBuildExt(build_ext):
remove_modules.append(line[])
input.close() + print "remove_modules: ", remove_modules
+
for ext in self.extensions[:]:
if ext.name in remove_modules:
self.extensions.remove(ext) + for ext in self.extensions[:]:
+ print "extensions: ", ext.name
+
# When you run "make CC=altcc" or something similar, you really want
# those environment variables passed into the setup.py phase. Here's
# a small set of useful ones.
@@ -, +, @@ class PyBuildExt(build_ext): # Platform-specific libraries
- if host_platform == 'linux2':
+ if host_platform == 'linux2' or host_platform == 'linux2-arm':
# Linux-specific modules
exts.append( Extension('linuxaudiodev', ['linuxaudiodev.c']) )
else:
missing.append('linuxaudiodev') - if (host_platform in ('linux2', 'freebsd4', 'freebsd5', 'freebsd6',
+ if (host_platform in ('linux2','linux2-arm' 'freebsd4', 'freebsd5', 'freebsd6',
'freebsd7', 'freebsd8')
or host_platform.startswith("gnukfreebsd")):
exts.append( Extension('ossaudiodev', ['ossaudiodev.c']) )
@@ -, +, @@ class PyBuildExt(build_ext):
## ext = Extension('xx', ['xxmodule.c'])
## self.extensions.append(ext) +# print "missing: ", missing
+# for ext in self.extensions:
+# print "extensions: ", ext.name
+
return missing def detect_tkinter_explicitly(self):
@@ -, +, @@ Topic :: Software Development
""" def main():
+ print "sys.path: ", sys.path
+ print "cross_compiling: ", cross_compiling
# turn off warnings when deprecated modules are imported
import warnings
warnings.filterwarnings("ignore",category=DeprecationWarning)
然后执行./mk2_make.sh可以看到:
sys.path: ['/home/pengdonglin/src/qemu/python_cross_compile/Python-2.7.13', '/home/pengdonglin/src/qemu/python_cross_compile/aarch32/build/lib.linux2-arm-2.7', '/home/pengdonglin/src/qemu/python_cross_compile/Python-2.7.13/Lib', '/home/pengdonglin/src/qemu/python_cross_compile/Python-2.7.13/Lib/plat-linux2', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload']
cross_compiling: True
build_extensions enter.
extensions: _struct
extensions: _ctypes_test
extensions: array
extensions: cmath
extensions: math
extensions: strop
extensions: time
extensions: datetime
extensions: itertools
extensions: future_builtins
extensions: _random
extensions: _collections
extensions: _bisect
extensions: _heapq
extensions: operator
extensions: _io
extensions: _functools
extensions: _json
extensions: _testcapi
extensions: _hotshot
extensions: _lsprof
extensions: unicodedata
extensions: _locale
extensions: fcntl
extensions: pwd
extensions: grp
extensions: spwd
extensions: select
extensions: parser
extensions: cStringIO
extensions: cPickle
extensions: mmap
extensions: syslog
extensions: audioop
extensions: crypt
extensions: _csv
extensions: _socket
extensions: _sha
extensions: _md5
extensions: _sha256
extensions: _sha512
extensions: termios
extensions: resource
extensions: nis
extensions: binascii
extensions: pyexpat
extensions: _elementtree
extensions: _multibytecodec
extensions: _codecs_kr
extensions: _codecs_jp
extensions: _codecs_cn
extensions: _codecs_tw
extensions: _codecs_hk
extensions: _codecs_iso2022
extensions: _multiprocessing
extensions: linuxaudiodev
extensions: _ctypes
builtin_module_names: ('__builtin__', '__main__', '_ast', '_bisect', '_codecs', '_collections', '_functools', '_heapq', '_io', '_locale', '_md5', '_random', '_sha', '_sha256', '_sha512', '_socket', '_sre', '_struct', '_symtable', '_warnings', '_weakref', 'array', 'binascii', 'cPickle', 'cStringIO', 'cmath', 'errno', 'exceptions', 'fcntl', 'gc', 'grp', 'imp', 'itertools', 'marshal', 'math', 'operator', 'posix', 'pwd', 'select', 'signal', 'spwd', 'strop', 'sys', 'syslog', 'thread', 'time', 'unicodedata', 'xxsubtype', 'zipimport', 'zlib')
remove_modules: ['DESTLIB=$(LIBDEST)', 'MACHDESTLIB=$(BINLIBDEST)', 'DESTPATH=', 'SITEPATH=', 'TESTPATH=', 'MACHDEPPATH=:$(PLATDIR)', 'EXTRAMACHDEPPATH=', 'TKPATH=:lib-tk', 'OLDPATH=:lib-old', 'COREPYTHONPATH=$(DESTPATH)$(SITEPATH)$(TESTPATH)$(MACHDEPPATH)$(EXTRAMACHDEPPATH)$(TKPATH)$(OLDPATH)', 'PYTHONPATH=$(COREPYTHONPATH)', 'posix', 'errno', 'pwd', '_sre', '_codecs', '_weakref', 'zipimport', '_symtable', 'GLHACK=-Dclear=__GLclear', 'xxsubtype']
extensions: _ctypes_test
extensions: datetime
extensions: future_builtins
extensions: _json
extensions: _testcapi
extensions: _hotshot
extensions: _lsprof
extensions: parser
extensions: mmap
extensions: audioop
extensions: crypt
extensions: _csv
extensions: termios
extensions: resource
extensions: nis
extensions: pyexpat
extensions: _elementtree
extensions: _multibytecodec
extensions: _codecs_kr
extensions: _codecs_jp
extensions: _codecs_cn
extensions: _codecs_tw
extensions: _codecs_hk
extensions: _codecs_iso2022
extensions: _multiprocessing
extensions: linuxaudiodev
extensions: _ctypes
Python build finished, but the necessary bits to build these modules were not found:
_bsddb _curses _curses_panel
_sqlite3 _ssl _tkinter
bsddb185 bz2 dbm
dl gdbm imageop
ossaudiodev readline sunaudiodev
zlib
To find the necessary bits, look in setup.py in detect_modules() for the module's name.
在刚开始的时候,self.extensions中还是全的,但是经过下面的处理后, 很多库都被remove了:
for ext in self.extensions[:]:
ext.sources = [ find_module_file(filename, moddirlist)
for filename in ext.sources ]
if ext.depends is not None:
ext.depends = [find_module_file(filename, moddirlist)
for filename in ext.depends]
else:
ext.depends = []
# re-compile extensions if a header file has been changed
ext.depends.extend(headers)
# platform specific include directories
ext.include_dirs.extend(incdirlist)
# If a module has already been built statically,
# don't build it here
if ext.name in sys.builtin_module_names:
self.extensions.remove(ext)
第15行的注释可以看到,如果sys.builtin_module_names中含有extensions中的库,那么这个库就会从extensions中remove。从目前的分析看,交叉编译的时候,setup.py的import sys导入的应该是PC机上面的环境,导致sys.builtin_module_names的值也是PC上面python运行环境的值(可以在PC的终端下输入python,查看sys.builtin_module_names的值)。
2、 解决
这里为了简单起见,我们只需把刚才出问题的判断注释掉,如下:
@@ -, +, @@ class PyBuildExt(build_ext): # If a module has already been built statically,
# don't build it here
- if ext.name in sys.builtin_module_names:
- self.extensions.remove(ext)
+ #if ext.name in sys.builtin_module_names:
+ # self.extensions.remove(ext) # Parse Modules/Setup and Modules/Setup.local to figure out which
# modules are turned on in the file.
然后重新配置、编译、安装, 最后重新制作ramdisk文件,启动板子,重新执行下面的测试:
[root@vexpress ]# python /usr/lib/python2./test/test___all__.py
test_all (__main__.AllTest) ... BaseHTTPServer
Bastion
CGIHTTPServer
ConfigParser
Cookie
DocXMLRPCServer
HTMLParser
MimeWriter
Queue
SimpleHTTPServer
... ...
'xml.sax.xmlreader', 'xmllib', 'xmlrpclib']
Following modules failed to be imported: ['ctypes.wintypes', 'dbhash', 'gzip', 'idlelib.AutoComplete']
ok
----------------------------------------------------------------------
Ran test in .345s
OK
可以看到,测试成功了。
下面开始一致sqlite3到板子上面,同时让python也增加多sqlite3的支持。
3、支持sqlite3
首先到http://www.sqlite.org/download.html 下载最新的sqlite3的源码,这里我用的是sqlite-autoconf-3170000.tar.gz,然后进行交叉编译,下面是交叉编译的脚本mk.sh:
#!/bin/bash
export PATH=/home/pengdonglin/src/qemu/aarch32/arm-2014.05/bin:$PATH ../sqlite-autoconf-/configure --host=arm-none-linux-gnueabi \
--prefix=`pwd` make -j4
make install
然后修改制作ramdisk的脚本:
#!/bin/bash sudo rm -rf rootfs
sudo rm -rf tmpfs
sudo rm -rf ramdisk* sudo mkdir rootfs
sudo cp ../busybox-1.24./_install/* rootfs/ -raf sudo mkdir -p rootfs/proc/
sudo mkdir -p rootfs/sys/
sudo mkdir -p rootfs/tmp/
sudo mkdir -p rootfs/root/
sudo mkdir -p rootfs/var/
sudo mkdir -p rootfs/mnt/ sudo cp etc rootfs/ -arf sudo cp -arf ../arm-2014.05/arm-none-linux-gnueabi/libc/lib rootfs/ #python
sudo mkdir -p rootfs/usr
pushd rootfs/usr
sudo cp -raf /home/pengdonglin/qemu/thiry_part/Python/aarch32/bin .
sudo cp -raf /home/pengdonglin/qemu/thiry_part/Python/aarch32/lib .
sudo cp -raf /home/pengdonglin/qemu/thiry_part/Python/aarch32/include .
sudo cp -raf /home/pengdonglin/qemu/thiry_part/Python/aarch32/share .
sudo /home/pengdonglin/qemu/aarch32/arm-2014.05/bin/arm-none-linux-gnueabi-strip lib/python*
popd 31 #sqlite3
32 sudo cp -raf /home/pengdonglin/qemu/thiry_part/SQlite3/aarch32/bin/* rootfs/bin/
33 sudo cp -raf /home/pengdonglin/qemu/thiry_part/SQlite3/aarch32/include/* rootfs/include/
34 sudo cp -raf /home/pengdonglin/qemu/thiry_part/SQlite3/aarch32/lib/* rootfs/lib/
35 sudo cp -raf /home/pengdonglin/qemu/thiry_part/SQlite3/aarch32/share/* rootfs/usr/share
sudo mkdir -p rootfs/dev/
sudo mknod rootfs/dev/tty1 c 4 1
sudo mknod rootfs/dev/tty2 c 4 2
sudo mknod rootfs/dev/tty3 c 4 3
sudo mknod rootfs/dev/tty4 c 4 4
sudo mknod rootfs/dev/console c 5 1
sudo mknod rootfs/dev/null c 1 3 sudo rm -rf rootfs/lib/*.a
sudo rm -rf rootfs/lib/*.la
sudo ../arm-2014.05/bin/arm-none-linux-gnueabi-strip rootfs/lib/* sudo dd if=/dev/zero of=ramdisk bs=1M count=100
sudo mkfs.ext4 -F ramdisk sudo mkdir -p tmpfs
sudo mount -t ext4 ramdisk ./tmpfs/ -o loop
sudo cp -raf rootfs/* tmpfs/
sudo umount tmpfs sudo gzip --best -c ramdisk > ramdisk.gz
sudo mkimage -n "ramdisk" -A arm -O linux -T ramdisk -C gzip -d ramdisk.gz ramdisk.img
这样在板子上面就可以使用sqlite3了,但是此时python还无法使用,需要重新编译python,并指定sqlite3的lib和include的路径,修改mk1_config.sh如下:
#!/bin/bash export PATH=/home/pengdonglin/qemu/aarch32/arm-2014.05/bin:$PATH ../Python-2.7./configure --prefix=`pwd` \
--host=arm-none-linux-gnueabi \
--build=x86_64-linux-gnu \
--enable-ipv6 \
--enable-shared \
ac_cv_file__dev_ptmx="yes" \
ac_cv_file__dev_ptc="no" \
LDFLAGS="-L/home/pengdonglin/qemu/thiry_part/SQlite3/aarch32/lib" \
CPPFLAGS="-I/home/pengdonglin/qemu/thiry_part/SQlite3/aarch32/include"
这样在Makefile调用setup.py时就会将sqlite3相关的模块编译进来,然后再次执行mk2_make.sh和mk3_install.sh,然后我们可以检查一下:
$ls aarch32/build/lib.linux2-arm-2.7/
array.so* _codecs_hk.so* cPickle.so* datetime.so* _heapq.so* _locale.so* _multiprocessing.so* _random.so* _socket.so* _sysconfigdata.pyc
audioop.so* _codecs_iso2022.so* crypt.so* _elementtree.so* _hotshot.so* _lsprof.so* nis.so* resource.so* spwd.so* syslog.so*
binascii.so* _codecs_jp.so* cStringIO.so* fcntl.so* _io.so* math.so* operator.so* select.so* _sqlite3.so* termios.so*
_bisect.so* _codecs_kr.so* _csv.so* _functools.so* itertools.so* _md5.so* ossaudiodev.so* _sha256.so* strop.so* _testcapi.so*
cmath.so* _codecs_tw.so* _ctypes.so* future_builtins.so* _json.so* mmap.so* parser.so* _sha512.so* _struct.so* time.so*
_codecs_cn.so* _collections.so* _ctypes_test.so* grp.so* linuxaudiodev.so* _multibytecodec.so* pyexpat.so* _sha.so* _sysconfigdata.py unicodedata.so*
可以看到,库已经很全了。
4、测试
重新制作ramdisk文件,启动系统。
编写测试sqlite3的脚本sq_demo.py如下:
#!/usr/bin/python import sqlite3 #open database
conn = sqlite3.connect('test.db')
print "Opened database successfully"; conn.execute('''CREATE TABLE COMPANY
(ID INT PRIMARY KEY NOT NULL,
NAME TEXT NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR(50),
SALARY REAL);''')
print "Table created successfully"; #insert
conn.execute("INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) \
VALUES (1, 'Paul', 32, 'California', 20000.00 )"); conn.execute("INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) \
VALUES (2, 'Allen', 25, 'Texas', 15000.00 )"); conn.execute("INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) \
VALUES (3, 'Teddy', 23, 'Norway', 20000.00 )"); conn.execute("INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) \
VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 )"); conn.commit()
print "Records created successfully"; #select
cursor = conn.execute("SELECT id, name, address, salary from COMPANY")
for row in cursor:
print "ID = ", row[0]
print "NAME = ", row[1]
print "ADDRESS = ", row[2]
print "SALARY = ", row[3], "\n" print "Operation done successfully"; #delect
conn.execute("DELETE from COMPANY where ID=2;")
conn.commit()
print "Total number of rows deleted :", conn.total_changes cursor = conn.execute("SELECT id, name, address, salary from COMPANY")
for row in cursor:
print "ID = ", row[0]
print "NAME = ", row[1]
print "ADDRESS = ", row[2]
print "SALARY = ", row[3], "\n" print "Operation done successfully"; conn.close()
下面是输出结果:
[root@vexpress ]# python /tmp/sq_demo.py
Opened database successfully
Table created successfully
Records created successfully
ID =
NAME = Paul
ADDRESS = California
SALARY = 20000.0 ID =
NAME = Allen
ADDRESS = Texas
SALARY = 15000.0 ID =
NAME = Teddy
ADDRESS = Norway
SALARY = 20000.0 ID =
NAME = Mark
ADDRESS = Rich-Mond
SALARY = 65000.0 Operation done successfully
Total number of rows deleted :
ID =
NAME = Paul
ADDRESS = California
SALARY = 20000.0 ID =
NAME = Teddy
ADDRESS = Norway
SALARY = 20000.0 ID =
NAME = Mark
ADDRESS = Rich-Mond
SALARY = 65000.0 Operation done successfully
完。
交叉编译Python-2.7.13到ARM(aarch32)—— 支持sqlite3的更多相关文章
- 交叉编译Python-3.6.0到aarch64/aarch32 —— 支持sqlite3
参考 https://datko.net/2013/05/10/cross-compiling-python-3-3-1-for-beaglebone-arm-angstrom/ 平台 主机: ubu ...
- 交叉编译Python-2.7.13到ARM(aarch32)平台
作者:彭东林 邮箱:pengdonglin137@163.com QQ:405728433 环境 主机: ubuntu14.04 64bit 开发板: qemu + vexpress-a9 (参考: ...
- 交叉编译Python-2.7.13到ARM(aarch64)平台
方法跟交叉编译Python-2.7.13到ARM(aarch32)平台基本一样, 不同的地方只是把工具链换成编译aarch64的工具链,这里可以参考用qemu搭建aarch64学习环境. 创建目录: ...
- 如何交叉编译Python到ARM-Linux平台(转)
源: 如何交叉编译Python到ARM-Linux平台
- ubuntu 交叉编译qt 5.7 程序到 arm 开发板
ubuntu 交叉编译qt 5.7 程序到 arm 开发板平台1 ubuntu 12.042 arm-linux-gcc 4.5.13 QT 5.74 开发板210 armcortex-A8 一 概述 ...
- ipython, 一个 python 的交互式 shell,比默认的python shell 好用得多,支持变量自动补全,自动缩进,支持 bash shell 命令,内置了许多很有用的功能和函数
一个 python 的交互式 shell,比默认的python shell 好用得多,支持变量自动补全,自动缩进,支持 bash shell 命令,内置了许多很有用的功能和函数. 若用的是fish s ...
- Python内置的urllib模块不支持https协议的解决办法
Django站点使用django_cas接入SSO(单点登录系统),配置完成后登录,抛出“urlopen error unknown url type: https”异常.寻根朔源发现是python内 ...
- Xamarin图表开发基础教程(13)OxyPlot框架支持的其它图表
Xamarin图表开发基础教程(13)OxyPlot框架支持的其它图表 除了以上提到的图表外,OxyPlot组件还包含了6种类型的其它图表,分别为等高线图.箱线图.饼图.热图.散点图和散点误差图,如图 ...
- VS Code Python 全新发布!Jupyter Notebook 原生支持终于来了!
VS Code Python 全新发布!Jupyter Notebook 原生支持终于来了! 北京时间 2019 年 10 月 9 日,微软发布了全新的 VS Code Python 插件,带来了众多 ...
随机推荐
- Hadoop权威指南: 专有数据类型
Writable 和 WritableComparable接口 Writable接口 ** Writable接口的主要目的是,当数据在网络上传输或从硬盘读写时,提供数据的序列化和反序列化机智 ** * ...
- JTable 的使用
JTable是Swing编程中的一种控件. 一.创建表格控件的各种方式:1) 调用无参构造函数. JTable table = new JTable(); 2) 以表头和表数据创建表格. Object ...
- gulp实时编译less,压缩合并requirejs模块文件
gulp的使用命令简单,就几个,gulp的简单使用教材可以参考一点的gulp使用教材(http://www.ydcss.com/archives/18). 下面就简单的介绍这些命令如何互相配合的完成前 ...
- 《JAVASCRIPT高级程序设计》节点层次和DOM操作技术
DOM可以将任何HTML和XML文档描绘成一个由多层次节点构成的结构.节点分为几种不同的类型,每种类型分别表示文档中不同的信息,每种类型都继承与Node接口,因此都共同享有一些属性和方法,同时,也拥有 ...
- [html5] 学习笔记-bootstrap介绍
1.Bootstrap介绍 Bootstrap 是最受欢迎的 HTML.CSS 和 JS 框架,用于开发响应式布局.移动设备优先的 WEB 项目. 2.下面对于官网上给出的最简单的一个bootstra ...
- We Chall-Training: ASCII—Writeup
MarkdownPad Document html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,ab ...
- sql的一点总结<一>
sql总结 1.常见的数据库对象有哪些?表(table) 视图(view) 序列(sequence) 索引(index) 同义词(synonym)存储过程(procedure) 存储函数(functi ...
- Java Web(七) JSTL标签库
在之前我们学过在JSP页面上为了不使用脚本,所以我们有了JSP内置的行为.行为只能提供一小部分的功能,大多数的时候还是会用java脚本,接着就使用了EL表达式,基本上EL表达式看似能满足我们的要求,它 ...
- URLencode 特殊字符 转义 遇上的坑
在项目中遇到一个问题,在webveiw和原生之间进行传值的时候,出现了一些encode的小问题.看起来很简单的问题,实际上却存在不小的坑. 首先说一下目前项目的结构,在一个activity中,webv ...
- 多源最短路径---Floyd-Warshall算法
摘自啊哈算法-知识分享,代码自己有改动,使得输出更直观. 小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间没有,如下图.为了节省经费以及方便计划旅程,小哼希望出发之前知道任意两个城市之间的最短 ...