分类 软件 下的文章

没错,就是这么皮

原因还是很奇葩,电脑上装的是VS2013,不支持C++11标准,而dlib要求编译器支持C++11标准。但是由于宇宙第一IDE体态太大,重新安装费时费力,且不打算花时间处理可能存在的卸载残留,便打起了GCC的主意。在网上查阅资料,发现GCC4.7之后就支持C++11标准了,于是打算使用配置的MinGW-W64 GCC 6.4.0进行配置。

首先修改setup.py: 第148-157行,替换:

        if platform.system() == "Windows":
            cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)]
            if sys.maxsize > 2**32:
                cmake_args += ['-A', 'x64']
            # Do a parallel build
            build_args += ['--', '/m'] 
        else:
            cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg]
            # Do a parallel build
            build_args += ['--', '-j'+str(num_available_cpu_cores(2))]

        cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg]
        # Do a parallel build
        build_args += ['--', '-j4']

将MSVC的编译选项换为GCC的,MinGW-W64默认编译64位程序。 其中最后一行的-j4指的是make的线程数目,如何自由修改想必不必多说。 由于可以随时使用源码包的源文件重新替换,可以直接修改文件而不做注释。

若需修改所使用的数学包,修改dlib/cmake_utils/find_blas.cmake: 第67-68, 74行

   pkg_check_modules(BLAS_REFERENCE openblas)
   pkg_check_modules(LAPACK_REFERENCE lapack)
   ...
   set(REQUIRES_LIBS "${REQUIRES_LIBS} openblas lapack")

这里使用的是pkg-config作为依赖管理器,在Windows中可以通过使用环境变量PKG_CONFIG_PATH来配置其搜索路径。简单地来说,就是通过使用pkg-config工具,可以快速地获得在编译时引入该库时所需要的选项。 比如OpenBLAS库,假设安装位置在X:\openblas\,库文件位于X:\openblas\lib\,则在该目录下应有一个pkgconfig文件夹,里面有openblas.pc文件,为pkg-config所需要的库描述文件,在make时自动生成。(按理说所有的.pc文件应该放在统一的目录下,方便查找和缩短查找路径) 则此时配置PKG_CONFIG_PATH为:set %PKG_CONFIG_PATH%=X:\openblas\lib\pkgconfig;%PKG_CONFIG_PATH% .pc文件为文本文件,里面的路径空格需要特殊处理,可以使用\来转义连接,也可以用直接把路径用双引号括起来。

编译时需要指定cmake参数:

setup.py build -G "MinGW Makefiles"  --set "CMAKE_C_COMPILER"="C:/Program Files/mingw-w64/bin/gcc.exe" --set "CMAKE_CXX_COMPILER"="C:/Program Files/mingw-w64/bin/g++.exe" --set "CMAKE_MAKE_PROGRAM"="C:/Program Files/mingw-w64/bin/make.exe"

分别指定使用MinGW(而不是MSVC)、C编译器、C++编译器和make命令进行编译。

编译过程中可能遇到的问题:

  1. 编译过程中可能遇到hypot命名空间未定义的问题,这是由于Python将C++的hypot重命名为_hypot导致的。 解决方案为在Python安装目录下include/pyconfig.h中引入#include <cmath>加入所缺失的定义。 必须要将该头文件作为第一个include,因为C++引入和顺序有一定的关系。

  2. 安装依赖库(如BLAS库)的时候,路径带有空格,在最后的生成pyd的时候,可能会导致路径错误。 推荐解决办法是重新安装依赖库之不含空格等特殊符号的路径下。 但是如果实在是懒,不想重新编译安装(指自己)的话,在此提供一种骚操作: cmake将链接时所使用的库作为命令行,以文本的形式存储起来。在本例中,存储位置为build\temp.win-amd64-3.6\Release\CMakeFiles\dlib_python.dir\linklibs.rsp。 思想是通过修改纠正其中生成错误的地方,达到目标效果。 -lgfortran也要手动加入,如果使用了gcc编译的BLAS库的话 想法是美好的,但是现实是残酷的:在每次运行setup.py build时,为了确保代码的完整性,会将这些中间文件重新生成一遍。 也就是说,即使修改了该文件,再重新时,该文件的内容又会被重新以原方式生成一遍。 好在Windows 10对于cmd做了一些对图形界面更加友好的修改,使得我们可以不用再去先右键再选中文字了。在经过多次试验后,发现当选中文字时,不但不会继续刷信息,而且运行的程序似乎也会暂停运行(类似断点的效果?)。 也就是说,可以通过在运行到链接.pyd库之前的每一行输出时,暂停检查linklibs.rsp文件,直到出现该消息为止。 通过这种方式可以顺利通过编译,链接完以后,就基本完成dlib的编译了。 至于升级pkg-config是否能解决问题,在下并不知道。

===================================================== 后续更新

在使用的时候,报了 系统找不到指定文件 的错误。也就是说,最终整个过程还是失败的。 猜测可能的原因是,编译时生成的是libdlib.a文件,属于linux操作系统下的静态库,而加载dlib库时,应该要动态加载dll文件,因而产生了该问题。同样,也不能排除文件格式和后缀不同所导致的问题。其原因有待后续深入探究。当然,最好的办法还是按照官方教程来,使用合适版本的VC++编译器来完成功能。

  1. 先到github上拉一份发布版本的源码包下来
  2. 安装python, bazel(Google的开源编译工具), 以及gcc等编译环境必备工具 其中bazel的新版本在编译时会报错,根据stackoverflow上的建议,使用1.17.2版本的,可在其github的发布页面找到下载。
  3. python安装numpy包。
  4. ./configure
  5. bazel build --config=mkl --config=opt //tensorflow/tools/pip_package:build_pip_package 生成轮子,用于pip安装。由于打算使用intel的mkl进行加速,添加了--config=mkl的选项。不需要的可以删除。

该错误通常在update语句报出。原因是企图在set子句中调用from子句中给表设立的别名。这个别名通常用于子句中的where子句的条件判定。 例:

UPDATE Tab
SET THIS.prop1 = (SELECT propx FROM Tab WHERE propy = THIS.propy)
FROM Tab THIS
WHERE propz = valz;

预期效果是希望将满足where条件的数据进新更新,实际上会报出如下错误: The multi-part identifier 'THIS.prop1' could not be bound. 原因是DBMS并搞不懂你的THIS和上面提到的Tab之间的关系。 解决方法:UPDATE Tab->UPDATE THIS,即把要更新的表名设置为为自己定义的别名即可。

参考: https://blog.csdn.net/dxnn520/article/details/7915198

实验课上,要求将一个角色的权限授予另一个角色。 在咕果上搜了老半天,结果只找到怎么把角色赋予用户。(汗,怎么这波技术含量这么低) 然后找到了ALTER ROLE ADD MEMBEREXEC sp_roleaddmember两个指令用于添加用户至角色。 用法:

ALTER ROLE <role-name> ADD MEMBER <user-name>
EXEC sp_roleaddmember [@rolename=]<role-name>, [@membername=]<user-name>

根据StackOverflow上该回答中一位用户所言,两者在SQL Server 2012中没有区别,参考资料如下: https://msdn.microsoft.com/en-us/library/ms189775.aspx https://msdn.microsoft.com/en-us/library/ms187750.aspx

但是在使用时,惊奇的发现在可以将Role作为参数填入以上操作的user-name部分,可以正常执行不会报错。 在子角色(user-name)的所有权限中查不到父角色(role-name)的权限,但是在父角色的成员表中可以看到子角色。 经过尝试后,发现直接对用户赋予子角色时,会自动给用户注册一个父角色的权限。 也就是说,直接把需要附加给角色的角色权限作为该角色的父角色,数据库便会在执行指令时自动赋予其父角色的权限。

例: 有两个角色,JuniorRoleSeniorRole,要将JuniorRole的权限赋予SeniorRole(显然高级用户通常应该拥有初级用户的全部权限),在SQL Server中可以这么做:

ALTER ROLE JuniorRole ADD MEMBER SeniorRole;

之后在进行用户授权时,ALTER ROLE SeniorRole add SeniorUser不仅会为SeniorUser赋予SeniorRole的角色,还会为其赋予JuniorRole的角色,目的达成。

创建一个与数据库创建者有相同权限的用户,可以设置自己默认的schema。

CREATE USER Esper
  WITHOUT LOGIN
  WITH DEFAULT_SCHEMA = MySchema;
go

GRANT CONNECT TO Esper;

ALTER ROLE db_owner ADD MEMBER Esper;

之后使用时在前面加一句

EXECUTE AS USER = 'Esper';
go

就可以让当前的批处理都以MySchema作为默认schema执行了。