Creating bindings for C libraries/zh CN

From Free Pascal wiki

English (en) español (es) français (fr) 日本語 (ja) русский (ru) 中文(中国大陆)‎ (zh_CN)


本页面描述了怎样创建一个pascal bindings(Pascal绑定)至C库。通常情况下Pascal不能直接使用C库。你必须为每个C函数、类型和变量创建一个转换。这里是H2Pas工具,它可以自动转换大部分常规C语句。 并且还有一个lazarus使用h2pas的图形界面GUI和其他工具来自动创建。此GUI可以帮助我们创建一个规则用于更新绑定,这样C库的下个版本会更容易转换。h2pas的优点是,它可以自动使用临时文件这样C的头文件不会被自动更改。


  • 取得你想转换的头文件。
  • 创建工作目录和为你的绑定取个名字。
  • 使用h2pas向导创建一个新的工程。
  • 添加 .h 文件到该工程。
  • 设置 h2pas 选项
  • 运行向导
  • 使用添加文本工具修复错误并再次运行向导。
  • 当 h2pas 没有运行错误后, 尝试编译和添加选项来美化输出。
  • 写一些测试程序来测试您的绑定
  • 在lazarus-ccr 或 Free Pascal 网站发布您的绑定。

Install tools

The h2pas tool comes with every normal fpc installation.

Install the h2paswizard package in the Lazarus IDE. Go to "Components -> Configure installed packages ...", select from the right list the H2PasWizard package and click 'Install selection', then 'Save and rebuild IDE'. Restart the IDE and you get a new menu entry: Tools -> h2pas

Fetch C header files

The C header files .h describes the interface of a C library. They are normally not provided with the library. You have to get the sources or the development package of the library. For example the C header files of the gtk libraries are in the package gtk+-devel.

Example: MPICH2

Download the mpich2-1.0.3.tar.gz from and unpack them. The .h files are under mpich2-1.0.3/src/include.

You can find more information about MPICH for FPC here.

Create a working directory and name your bindings

Create a directory with a useful name. A name should not contain special characters, like spaces, umlaute, points or commas. Copy the .h files.

Example: MPICH2

The h2p directory will be used for the pascal files. The h2p/c_sources directory will be used for the .h files.

 mkdir -p h2p/c_sources
 cp mpich2-1.0.3/src/include/*.h h2p/c_sources/

Create a new h2pas project with the h2pas wizard

Open the h2pas wizard: "Tools -> h2pas". This will open a window. You can switch between this window and the other IDE windows. Your last h2pas project will be loaded automatically. To create a new project click on "Settings -> New/Clear settings". Then click on the bottom button "Save settings" and choose a filename.

Note: If this is the first time you have used the h2pas wizard, you need to use the wizard's "Settings" tab to tell the wizard where to find the h2pas.exe converter program. The h2pas.exe converter lives in the same directory as the FreePascal compiler fpc.exe - if you downloaded FPC as part of Lazarus it will be in ...\Lazarus\fpc\version\bin. Then save the settings so you don't have to do this again.

Example: MPICH2

Click on "Settings -> New/Clear settings". Then click on the bottom button "Save settings" and save it as h2p/mpi2.h2p.

Add the .h files to the h2pas-project

In the "C header files" page you can add/delete the .h files. You can enable/disable .h files to convert only part of the files.

Example: MPICH2

Click on "C header files -> Add .h files ..." and select "mpi.h" and "mpio.h". They will be enabled automatically. Select the mpi.h file and click "Merge all but this", so that the wizard combines all header files into one unit (mpi.pas).

Setup the h2pas options

Under "h2pas Options" you can set the parameters for the h2pas program.

Example: MPICH2

  • Enable -e, -D, -p, -w and disable all others.
  • The -l library path is "mpich".
  • Output extension is ".pas"
  • Output directory is h2pas/, which is the default, so leave it empty

Run the wizard

Click on the bottom button "Run h2pas". This will copy the <example>.h file to a temporary <example>.tmp.h file and run the tools listed under "Before h2pas". Then it runs h2pas to convert the <example>.tmp.h into <example>.inc or <example>.pas or whatever output extension you setup on the h2pas page. Then it runs the tools listed under "After h2pas" on the output files.

If h2pas finds a syntax error, the IDE will open the example.tmp.h file and jumps to the error line. h2pas often only reports 'syntax error', which is very unspecific. See Common problems when converting C header files.

Example: MPICH2

The h2pas wizard already contains all tools to convert all the specials of this header file, so h2pas runs without errors. But the created unit is not yet ready. Read further.

Add the following to the Undefines property:


Add the following to the Defines property:


Publish your bindings on lazarus-ccr or Free Pascal


Writing your own converter tools

Using the tool "Search and replace"

Many things like renaming a variable can be done by the Search and replace tool. Add the tool via the Add new tool button on either the 'Before h2pas' or the 'After h2pas' page. Then set the SearchFor, ReplaceWith, Options and Caption property.

Example: rename an identifier Tguint to guint

Property Value
Caption Rename Tguint to guint
SearchFor Tguint
ReplaceWith guint
Options [trtMatchCase,trtWholeWord]

Example: rename several identifiers

Rename Tguint to guint, Tgulong to gulong, Tgint to gint:

Property Value
Caption Rename Tguint to guint
ReplaceWith $1
Options [trtMatchCase,trtWholeWord,trtRegExpr]

Example: MPICH2

Removing Makro MPI_DUP_FN

The MPI_DUP_FN is defined two times in the mpi C headers. Once as a macro to something that does not exist, and later to a real function. So, the first should be deleted.

Add a 'Search and replace' tool to the before H2Pas tools (at the end) with the following settings:

Property Value
Caption Remove dummy define MPI_DUP_FN
Name RemoveDummyDefineMPI_DUP_FN
Options [trtMatchCase,trtRegExpr]

Removing typecasts to MPI_DUP_FN

Add a 'Search and replace' tool to the before H2Pas tools (at the end) with the following settings:

Property Value
Caption Remove MPI_DUP_FN Makros
Name Remove_MPI_DUP_Func
^#define .*MPI_DUP_FN\).*$
Options [trtMatchCase,trtRegExpr]

Removing functions MPIO_Test, PMPIO_Test, MPIO_Wait and PMPIO_Wait

The MPIO_Test, PMPIO_Test, MPIO_Wait and PMPIO_Wait functions are defined twice and redefined via macro. So, the functions can be removed:

Add a 'Search and replace' tool to the before H2Pas tools (at the end) with the following settings:

Property Value
Remove Func P?MPIO_(Test|Wait)
Name RemoveFuncP_MPIO_Test_Wait
^int P?MPIO_(Test|Wait).*$
Options [trtMatchCase,trtRegExpr]

Improving an existing tool

You found a bug and want to fix it or you want to extend one of the above tools. Great!

Most of the above tools are defined in the h2pasconvert unit, which is part of the h2paswizard package. Basically a tool needs a classname, a description and an Execute method. To test/debug a tool outside the IDE and save a lot of compilation time, see the project components/simpleideintf/examples/testh2pastool.lpi. Compile it and start it on a console/terminal with the filename of a .h file as first command parameter. For example:

 ./testh2pastool files/h2pastest.pas

Writing a custom tool

You can write your own conversion tools and register them in the IDE easily. Start a package and a add a new unit (say unit1) for your new class. See the existing tools as example and read the prior section. When you wrote a new tool and tested it with the above simpleideintf project, then register it in the IDE: Add a register procedure to your unit (unit1), like the following (pseudo code):

  Classes, ..., IDETextConverter;

  TYourToolClass = class(TCustomTextConverterTool)
    class function ClassDescription: string; override;
    function Execute(aText: TIDETextConverter): TModalResult; override;

procedure Register;


procedure Register;

Do not forget to enable the register checkbox of the unit in the package editor, otherwise the Register procedure will not be called by the IDE. Then install your package in the IDE.

Future work / Missing stuff

  • A tool to convert static linked procedures to dynamic linked procedure variables
  • A tool to fix functions without parameter names by searching the .c files. This could also add a comment, in which c file it found the function.
  • Find missing identifiers and let the user check which one to comment or replace with base types.
  • Create a list of macro functions, which were half translated.
typedef struct page
   u32int present    : 1;   // Page present in memory
   u32int rw         : 1;   // Read-only if clear, readwrite if set
   u32int user       : 1;   // Supervisor level only if clear
   u32int accessed   : 1;   // Has the page been accessed since last refresh?
   u32int dirty      : 1;   // Has the page been written to since last refresh?
   u32int unused     : 7;   // Amalgamation of unused and reserved bits
   u32int frame      : 20;  // Frame address (shifted right 12 bits)
} page_t;


    Unsigned_7  = 0 .. (1 shl 7)  - 1;
    Unsigned_20 = 0 .. (1 shl 20) - 1;

    page_t = bitpacked record
       present  : boolean;
       rw       : boolean;
       user     : boolean;
       accessed : boolean;
       dirty    : boolean;
       unused   : Unsigned_7;
       frame    : Unsigned_20;

Lazarus/FPC Libraries