8.27.2018

Python 3 call C by ctypes

point.h
/* Point.h */
/* Simple structure for ctypes example */
typedef struct {
    int x;
    int y;
} Point;

point.c
/* Point.c */
#include "stdio.h"
#include "point.h"

/* Display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_point(void) {
    static int counter = 0;
    Point point = { counter++, counter++ };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}


For mingw32:
gcc -fPIC -shared -msse4.2 point.c -o point.dll

使用point.py連point.dll:
import ctypes
def wrap_function(lib, funcname, restype, argtypes):
    """Simplify wrapping ctypes functions"""
    func = lib.__getattr__(funcname)
    func.restype = restype
    func.argtypes = argtypes
    return func
   
class Point(ctypes.Structure):
    _fields_ = [('x', ctypes.c_int), ('y', ctypes.c_int)]
    def __repr__(self):
        return '({0}, {1})'.format(self.x, self.y)
       
libc = ctypes.CDLL('point.dll')
show_point = wrap_function(libc, 'show_point', None, [Point])
p = Point(1, 2)
show_point(p)

正常的話,會出現:
Point in C      is (1, 2)

如果出現以下錯誤訊息:
OSError: [WinError 193] %1 is not a valid Win32 application

可能是因為Python是x64版的,但是dll是32 bits
詳參:

Error loading DLL in python, not a valid win32 application


ctypes更複雜的例子,可參考:

8.25.2018

"undefined reference to" 問題解決方法

在此,只舉個靜態庫的例子,假設源碼如下。
先把test.c編譯成靜態庫(.a)文件
  1. gcc -c test.c
  2. ar -rc test.a test.o
至此,我們得到了test.a文件。我們開始編譯main.c
  1. gcc -c main.c
這時,則生成了main.o文件,然後我們再通過如下命令進行連結希望得到可執行程序。
你會發現,編譯器報錯了:
  1. /tmp/ccCPA13l.o: In function `main':
  2. main.c:(.text+0x7): undefined reference to `test'
  3. collect2: ld returned 1 exit status
其根本原因也是找不到test函數的實現文件,由於該test函數的實現在test.a這個靜態庫中的,故在連結的時候需要在其後加入test.a這個庫,連結命令修改為如下形式即可。
  1. gcc -o main main.o ./test.a //註:./ 是給出了test.a的路徑
【擴展】:同樣,為了把問題說清楚,上面我們把代碼的編譯連結分開了,如果希望一次性生成可執行程序,則可以對main.c和test.a執行如下命令。
  1. gcc -o main main.c ./test.a //同樣,如果不加test.a也會報錯


原文網址:https://read01.com/GAQBKx.html

.o, .a, .so, .la 如何產生

o, .a, .so, .la 如何產生

  • 建立 .o
    $ gcc -c test.c
  • 建立 .a
    $ ar -r libtest.a test1.o test2.o
  • 建立動態函式庫 .so
    $ gcc -Wall -fpic -shared test1.c test2.c -o libtest.so
  • 鍊結函式庫
    $ gcc -Wall -fpic -shared -Ltest test3.c -o libtest.so
  • 建立 .la, .la 一般會使用 Makefile 產生, 可以透過下述命令產生:
    $ libtool --mode=link gcc -o libmylib.la -rpath /usr/lib –L/usr/lib –la

Linux 的 .a / .so / .la 函式庫的差異

  • .o (obj file) 是目標物件函式庫, 等同於 Windows 的 .obj
  • .a 為靜態函式庫, 可以是 一個 或 多個 .o 合在一起, 用於靜態連結
  • .la 為 libtool 生成的共享函式庫, 其實是個設定的檔案. 可以用 file 代替
  • .la 可用 vi 來查看
  • .so 為動態函式庫, 類似 Windows 的 DLL(Dynamic-link library)檔.
  • 補充: 還有一種附檔名為 .ko 的檔案, 不過它是 Linux 核心使用的動態連結文件, 屬於模組程式, 用來在 Linux 系統啟動時, 加掛核心模組用.

gcc -fPIC -shared -msse4.2 great_module.c -o great_module.dll




聊聊Python ctypes 模块


摘要:模块ctypes是Python内建的用于调用动态链接库函数的功能模块,一定程度上可以用于Python与其他语言的混合编程。由于编写动态链接库,使用C/C++是最常见的方式,故ctypes最常用于Python与C/C++混合编程之中。
=================================================================
1. ctypes 的原理以及优缺点
从ctypes的文档中可以推断,在各个平台上均使用了对应平台动态加载动态链接库的方法,并通过一套类型映射的方式将Python与二进制动态链接库相连接。通过阅读ctypes本身的代码也可以印证这个推断(/Modules/_ctypes/_ctypes.c和/Modules/_ctypes/callproc.c)。在Windows平台下,最终调用的是Windows API中LoadLibrary函数和GetProcAddress函数,在Linux和Mac OS X平台下,最终调用的是Posix标准中的dlopen和dlsym函数。ctypes 实现了一系列的类型转换方法,Python的数据类型会包装或直接推算为C类型,作为函数的调用参数;函数的返回值也经过一系列的包装成为Python类型。也就是说,PyObject* <-> C types的转换是由ctypes内部完成的,这和SWIG是同一个原理。
从ctypes的实现原理不难看出:
ctypes 有以下优点:
  • Python内建,不需要单独安装
  • 可以直接调用二进制的动态链接库
  • 在Python一侧,不需要了解Python内部的工作方式
  • 在C/C++一侧,也不需要了解Python内部的工作方式
  • 对基本类型的相互映射有良好的支持
ctypes 有以下缺点:
  • 平台兼容性差
  • 不能够直接调用动态链接库中未经导出的函数或变量
  • 对C++的支持差
就个人的经验来看,ctypes 适合于“中轻量级”的Python C/C++混合编程。特别是遇到第三方库提供动态链接库和调用文档,且没有编译器或编译器并不互相兼容的场合下,使用ctypes特别方便。值得注意的是,对于某种需求,在Python本身就可以实现的情况下(例如获取系统时间、读写文件等),应该优先使用Python自身的功能而不要使用操作系统提供的API接口,否则你的程序会丧失跨平台的特性。
2. 一个简单的例子
作为Python文档的一部分,ctypes 提供了完善的文档。但没有Windows API编程经验的初学者读ctypes文档仍然会晕头转向。这里举一个小例子,尽力避开Windows API以及POSIX本身的复杂性,读者只需要了解C语言即可。
在尝试本节例子之前,依然要搭建Python扩展编程环境。见 搭建Python扩展开发环境 - 蛇之魅惑 - 知乎专栏
首先我们写一个C语言的小程序,然后把它编译成动态链接库。
//great_module.c
#include 

#ifdef _MSC_VER
    #define DLL_EXPORT __declspec( dllexport ) 
#else
    #define DLL_EXPORT
#endif

DLL_EXPORT int great_function(unsigned int n) {
    return _mm_popcnt_u32(n);
}
这个源文件中只有一个函数 great_function,它会调用Intel SSE4.2指令集的POPCNT指令(封装在_mm_popcnt_u32中),即计算一个无符号整数的二进制表示中“1”的个数。如果你的电脑是2010年前购买的,那么很可能不支持SSE4.2指令集,你只需要把return这一行改为 return n+1;即可,同样能够说明问题。
调用_mm_popcnt_u32需要包含Intel 指令集头文件nmmintrin.h,它虽然不是标准库的一部分,但是所有主流编译器都支持。
中间还有一坨#ifdef...#else...#endif,这个是给MSVC准备的。因为在MSVC下,动态链接库导出的函数必须加 __declspec( dllexport ) 进行修饰。而gcc(Linux和Mac OS X的默认编译器)下,所有函数默认均导出。
接下来把它编译为动态链接库。Windows下动态链接库的扩展名是dll,Linux下是so,Mac OS X下是dylib。这里为了方便起见,一律将扩展名设定为dll。
Windows MSVC 下编译命令:(启动Visual Studio命令提示)
cl /LD great_module.c /o great_module.dll 
Windows GCC、Linux、Mac OS X下编译命令相同:
gcc -fPIC -shared -msse4.2 great_module.c -o great_module.dll
写一个Python程序测试它,这个Python程序是跨平台的:
from ctypes import *
great_module = cdll.LoadLibrary('./great_module.dll')
print great_module.great_function(13)
整数13是二进制的1101,所以应该输出3

8.22.2018

Replacements for switch statement in Python?

Replacements for switch statement in Python?


You could use a dictionary:
def f(x):
    return {
        'a': 1,
        'b': 2,
    }[x]

If you'd like defaults you could use the dictionary get(key[, default]) method:
def f(x):
    return {
        'a': 1,
        'b': 2
    }.get(x, 9)    # 9 is default if x not found

8.21.2018

Python - Initializing Multiple Lists/Line

This is terribly ugly:
psData = []
nsData = []
msData = []
ckData = []
mAData = []
RData = []
pData = []
Is there a way to declare these variables on a single line?

Ans:down voteaccepted
alist, blist, clist, dlist, elist = ([] for i in range(5))

8.03.2018

嘸蝦米輸入法的灰色免費方案 for Windows 10

簡單說就是rime + 無蝦米設定檔:
1. Download and install rime
2. Go to https://github.com/amoshyc/myliu and download all files
3. 將 repo 中除了 README.md 外的所有檔案放至C:\Program Files (x86)\Rime\weasel-0.11.1\data 中。
(Linux 設定法,可參考https://amoshyc.github.io/blog/2018/install-liu-with-rime.html)
4. 在右下角rime 按滑鼠右鍵打開選單 -> 輸入法設定 -> 勾選 嘸蝦米 -> 中 -> 中
5. Ctrl + ` 切換輸入法

舊的Windows可參考:

嘸蝦米輸入法的三個灰色免費方案 for Windows


4.24.2018

UVa 465 - Overflow這題似乎有點詭異

不知為什麼,我的465 - Overflow這題,Accepted被拿掉了,
因此,我再次挑戰這題,發現同樣的程式邏輯用到__builtin_add_overflow
或者 __builtin_mul_overflow,會得到W.A.
另外,如果檢查strtol的errno == ERANGE,一樣會得到W.A.
最後Google別人的AC code,他是用sscanf來轉換char *,
我跟著用,才得到A.C. 慚愧…

3.27.2018

Enable Fedora 27 Icons on Desktop

Install Gnome Tweak Tool on Fedora 27

1. sudo dnf makecache
2. sudo dnf install gnome-tweak-tool
3. Tweaks ->  Desktop -> Icons on Desktop

2.17.2018

AQ vs Leela vs RN with Windows 10 version

測試環境:
OS: Windows 10 x64
Go GUI: Sabaki
AQ 2.1.1
Leela 0.11.0
RN 4.32

GPU: Nvidia GTX 960M
CPG: i7-6700HQ

AQ 2.1.1:
下載回來Windows版後,修改aq_config.txt:
-komi =6.5

Leela 0.11.0:
使用參數 --gtp

RN 4.32:
下載回來Windows版後,直接使用

Sabaki:
使用預設的開局 (komi = 6.5)

測試結果:
首先 AQ 2.1.1 vs Leela 0.11.0
AQ 兩次執黑勝 Leea
AQ 兩次執白也勝 Leea

認為棋力 AQ 2.1.1 > Leela 0.11.0

由於 RN 4.32執黑 AQ 2.1.1執白在我的電腦會有問題,
所以 RN 4.32執白 vs AQ 2.1.1執黑,
測試一場,結果AQ 2.1.1勝利。

接下來測試,
RN 4.32 執黑 vs Leela 0.11.0執白,
結果 Leela 0.11.0勝利。

推測棋力 AQ 2.1.1 > Leela 0.11.0 > RN 4.32
但是網路上大都評論說 RN 比 Zen6 甚或 Leela 強上很多,
只是有人實測也是RN輸給Leela (參數和版本跟我測的不見得相同)
參:兩個圍棋AI引擎的自動對奕-RN vs. Leela


有一點值得注意的是,若是AQ 2.1.1的-use pondering =off
則對決Leela 0.11.0測了兩場皆輸 (忘了執黑還是執白),
所以pondering一定要開,才能發揮AQ的實力。

2.09.2018

Android 2D Game Tutorial for Beginners (轉貼)

Android 2D Game Tutorial for Beginners


This document is based on:
  • Android Studio 1.5

Target of the document is help you to become acquainted with a few simple techniques in  programming Android Game 2D. Include:
  • Use SuffaceView
  • Drawing on a Canvas
  • The motion of the game character.
  • Interactions with the player's gestures
In this document, I will guide you step by step, therefore, you need to read and practice up to down. We will write each version of the game from 1 to the final version.

2- Create a Game Project

Note that you're creating a 2D game on Android, so the interface of the game must be drawn by you, so you do not need aactivity_main.xml file.
OK, your Project was created.

3- Preparing Images and sounds

You need a few images
  • chibi1.png


  • chibi2.png



  • explosion.png





The Audio file of the explosion.
Background sound:
Copy these images to the drawable folder of project. Create raw folder, and copy explosion.wav & background.mp3 to this folder.

4- Setting fullscreen (Version:1)

With games, you need to set the background image and an important thing is that you need to set FullScreen mode.
Your MainActivity class must extends from the Activity class .
MainActivity.java (Version: 1)
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package org.o7planning.androidgame2d;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Set fullscreen
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        // Set No Title
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
    }
}
Running apps: