Code Monkey home page Code Monkey logo

cffi-lua's Introduction

cffi-lua

Build Status

This is a portable C FFI for Lua, based on libffi and aiming to be mostly compatible with LuaJIT FFI, but written from scratch. Compatibility is preserved where reasonable, but not where not easily implementable (e.g. the parser extensions for 64-bit cdata and so on). Thanks to libffi, it works on many operating systems and CPU architectures. The cffi-lua codebase itself does not contain any non-portable code (with the exception of things such as Windows calling convention handling on x86, and some adjustments for big endian architectures). Some effort was also taken to ensure compatibility with custom Lua configurations (e.g. with changed numeric type representations), though this is not tested or guaranteed to work (patches welcome if broken).

Unlike LuaJIT's ffi module or other efforts such as luaffifb, it works with every common version of the reference Lua implementation (currently 5.1, 5.2, 5.3 and 5.4, 5.0 could be supported but wasn't considered worth it) as well as compatible non-reference ones (like LuaJIT). Functionality from newer Lua versions is also supported, when used with that version (e.g. with 5.3+ you will get seamless integer and bit-op support, with 5.4 you will get metatype support for to-be-closed variables, and so on).

Since it's written from scratch, having 1:1 bug-for-bug C parser compatibility is a non-goal. The parser is meant to comply with C11, plus a number of extensions from GCC, MSVC and C++ (where it doesn't conflict with C).

The project was started because there isn't any FFI for standard Lua that's as user friendly as LuaJIT's and doesn't have portability issues.

Current status

See STATUS.md.

Notable differences from LuaJIT

  • Equality comparisons against nil always result in false
  • Equality comparisons between cdata and Lua values are always false
  • Passing unions (or structs containing unions) is not supported on all platforms
  • Bitfields are not supported
  • Several new API extensions

Equality comparions work this way due to limitations of the Lua metamethod semantics. Use cffi.nullptr instead. The other limitations are caused by libffi not supporting these features portably.

Dependencies

The dependencies are kept intentionally minimal.

  • A C++ compiler supporting the right subset of C++14
  • Lua 5.1 or newer (tested up to and including 5.4) or equivalent (e.g. LuaJIT)
  • libffi (built with meson subproject if missing)
  • meson

Optional dependencies:

  • pkg-config (for automated Lua finding)
  • A Lua executable (only for tests)

These toolchains have been tested:

  • GCC 7+ (all platforms)
  • Clang 8+ (all platforms)
  • Visual Studio 2017+ (with updates)

Other toolchains may also work. The theoretical minimum is GCC 4.8 and Clang 3.4 (an updated VS 2017 is already the minimum, older versions are missing necessary language features). It is ensured that no non-standard extensions are used, so as long as your compiler is C++14 compliant, it should work (technically there are some GCC/Clang/MSVC-specific diagnostic pragmas used, but these are conditional and only used to control warnings).

The module should work on any CPU architecture supported by libffi. The CI system tests a large variety of CPU architectures (see STATUS.md). If you encounter any issues on yours, please send patches or at least report them so they can be fixed.

The pkg-config tool is optional when using -Dlua_version=custom and vendored libffi (through build options or subproject). However, for custom libffi, you will need to manually specify what to include and link.

Building

On Unix-like systems:

$ mkdir build
$ cd build
$ meson ..
$ ninja all

This will configure the module for the default Lua version in your system. If your system does not provide a default lua.pc pkg-config file, you will need to explicitly set the version with e.g. -Dlua_version=5.2 passed to meson. You will also need to do this if you with to compile for a different Lua version than your default lua.pc provides.

By default, a Lua loadable module will be built. This module can be installed in a path that Lua expects. On Unix-like systems, the ninja install target can do that.

There is also an option to build a static library, by passing -Dstatic=true to meson. This is mainly intended for either application usages that will embed the FFI, or for various specialized platforms that do not support shared libraries or don't have a version of Lua configured to support modules. This version is usually not meant to be distributed. To use the static version, you will need to declare the luaopen_cffi symbol with the usual Lua function signature, lua_pushcfunction it on the stack and for example store it in package.preload.

You can also pass luajit to -Dlua_version to build against LuaJIT (it will use luajit.pc then). Additionally, if you have a different Lua implementation than that but it still provides the same compliant API, you can bypass the check with -Dlua_version=custom and then provide the appropriate include path and linkage via CXXFLAGS and LDFLAGS.

It is also possible to pass -Dlua_version=vendor, in which case the library will be taken from deps and the includes from deps/include. The deps directory can be either in the source root or in the directory you run meson from.

Keep in mind that on Unix-likes, it is not necessary to actually link against the Lua library. Even when using pkg-config, the build system will always remove the linkage. The Lua symbols are instead supplied to the module through the executable it's loaded from. This does not work on Windows, where you actually need to link against the DLL for Lua modules to work.

When using homebrew on macOS, its libffi is not installed globally. Therefore, you will need to set your PKG_CONFIG_PATH so that pkg-config can find its .pc file.

You can also use -Dlibffi=custom if you wish to completely override what libffi is used. In that case you will need to provide the right include path in CXXFLAGS so that either <ffi.h> or <ffi/ffi.h> can be included, plus linkage in LDFLAGS.

When libffi cannot be found in the system and you have not overridden how it is supplied, a Meson subproject will be automatically used (and libffi will be statically linked into the module).

It is also possible to pass -Dlua_install_path=... to override where the Lua module will be installed. See below for that.

The shared_libffi option will make libffi provide dllimport-decorated APIs on Windows; for Lua this is the default as there is always a DLL. On other systems, it does nothing. This is not strictly necessary, but it will make things faster when you're really using dynamic versions of those, and it's not possible to autodetect. Usually, you should be using static libffi on Windows.

Windows and MSVC style environment

To build on Windows with an MSVC-style toolchain, first get yourself the right version of Lua and optionally a binary distribution of libffi. They must be compatible with the runtime you're targeting.

Drop the .lib files (import lib for Lua, optionally static or import lib for libffi) in the deps directory (either in the source root or the directory you are running meson from). The naming is up to you, meson will accept library names with or without lib prefix, and the build system accepts both unversioned and versioned to cover all environments. Usually, for Lua you will have something like lua53.lib. Also, if providing your own libffi, drop the include files (ffi.h and ffitarget.h) into deps/include, same with the Lua include files.

It is recommended that you always use a static library for libffi if providing one.

Drop any .dll files in the deps directory also. This would be the Lua dll file typically (e.g. lua53.dll).

If you wish to run tests, also drop in the Lua executable, following the same naming scheme as the .dll file (or simply called lua.exe). If you don't do that, you will need to pass -Dtests=false to meson as well.

Afterwards, run meson from the build directory (create it), like this:

meson .. -Dlua_version=vendor

Add -Dlibffi=vendor if providing a libffi.

Then proceed with the usual:

ninja all
ninja test

Examples of such environment are the Visual Studio environment itself and also Clang for Windows by default.

Windows and MinGW/MSYS style environment

This environment is Unix-like, so install the necessary dependencies as you would on Linux. In an MSYS2 environment, this would be something like:

pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-pkg-config
pacman -S mingw-w64-x86_64-meson
pacman -S mingw-w64-x86_64-lua

Particularly for MSYS2, you should use dependencies from just one repo, as e.g. meson installed from the MSYS2 repo won't detect mingw-w64 libraries and so on.

After that, proceed as you would on Linux:

meson .. -Dlua_version=5.3

You might also want to provide -static-libgcc -static-libstdc++ in LDFLAGS if you wish to distribute the resulting module/library, otherwise they will carry dependencies the libgcc and libstdc++-6 DLLs.

Compile and test with:

ninja all
ninja test

For plain MinGW, this will be similar, except you will need to manually provide your the dependencies.

Installing

$ ninja install

This will install either the module or the static library depending on how you have configured the build.

By default, the Lua module will install in $(libdir)/lua/$(luaver), e.g. /usr/lib/lua/5.2. This is the default for most Lua installations. You can override that with -Dlua_install_path=.... The path is the entire installation path. You can insert @0@ in it, which will be replaced with the Lua version you're building for (e.g. 5.2). No other substitutions are performed.

The goal of this is to make sure the module will be installed in a location contained in your Lua's package.cpath.

Testing

The module uses a native Lua executable to run tests. Since by default tests are enabled, the build system will search for the executable. If your copy of Lua is in a non-standard path, you can use -Dlua_path=... when configuring to explicitly specify where the executable is stored.

Tests are only runnable when all of the following is met:

  • You are not cross-compiling
  • You are doing a module build (i.e. not -Dstatic=true)
  • The Lua executable matches the language version you are building for

Either way, you can run tests with the following:

$ ninja test

You can see the available test cases in tests, they also serve as examples.

Some of the tests only work if cffi is built with working cffi.load. This is nearly always true when you are building a module, since cffi supports more targets than Lua itself with module loading.

You can also run the individual test cases standalone, like this:

$ lua path/to/cffi/tests/runner.lua path/to/test/case.lua

The environment variable TESTS_PATH can be used to manually specify the tests directory. Usually this is not necessary as it's automatically figured out.

You can also specify CFFI_PATH as the path where cffi.so or .dll is stored. By default, it is assumed default package.cpath contains it somewhere.

Additionally, TESTLIB_PATH should be specified as a path to the test support library. This library contains utilities used by some of the tests, like various native calls and global symbols. By default, it is stored in build/tests. If you do not specify this, tests requiring it will not run.

Test cases ordinarily do not print anything to standard output or error. If the return code is 0, the test has succeeded. If it is 77, the test was skipped, e.g. because of the testlib not being found. In case of hard failures, an assertion error will be raised.

cffi-lua's People

Contributors

ffontaine avatar jan200101 avatar q66 avatar vsergeev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cffi-lua's Issues

segfaults in ffi::newctype

Hello,

thank you for the previous patches.

I am currently stuck with the following issue. When running a "complex" program at some point I get segfaults in ffi::newctype. Below is a typical example of a trace obtained with gdb:

#0  0x0000555555564385 in sweeplist ()
#1  0x0000555555564475 in sweepstep ()
#2  0x00005555555658b4 in singlestep ()
#3  0x0000555555566020 in luaC_step ()
#4  0x000055555555e137 in lua_newuserdatauv ()
#5  0x00007ffff73fb4db in operator new (n=40, L=0x5555557942a8) at ../src/lua.hh:158
#6  0x00007ffff73fa83e in ffi::newctype<ast::c_type>(lua_State *, <unknown type in lib/lua/5.4/cffi.so, CU 0xca9, DIE 0x51d2>) (
    L=0x5555557942a8, args#0=<unknown type in lib/lua/5.4/cffi.so, CU 0xca9, DIE 0x51d2>) at ../src/ffi.hh:282
...

Unfortunately I could not reproduce this issue with a minimal example. The segfaults happen in several of my use cases and are always triggered by the previous sequence: ffi::newctype/sweeplist. It does not happen on the first call to ffi::newctype but rather after O(100) calls or so.

Sorry, this is not very helpful but I don't know what to check at this point? Please, let me know if there are extra values that would be meaningful to be printed out, e.g. using gdb?

When using LuaJIT/ffi I have no segfaults.

[Question] C++14 vs ANSI C

First of all, thank you very much for the library, it's awesome!

Any reason to implement it using C++14 instead of ANSI C like the Lua language?

Type comparison (istype) differs from LuaJIT

Hello,

Thank your for your help on the previous issue.

this one might be intended? I came across the following difference between LuaJIT/ffi and cffi:

local ffi = jit and require('ffi') or require('cffi')

ffi.cdef([[
struct structure {
    double scalar;
    double vector[3];
};
]])

local structure = ffi.new('struct structure')
print(ffi.istype('double [3]', structure.vector))
print(ffi.istype('double (&)[3]', structure.vector))

the last istype returns true with LuaJIT/ffi but false with cffi, i.e. double [3] and double (&)[3] are considered as the same type in one case but different types in the second case.

windows build issues

Hello guys

Trying to build cffi-lua for windows x64. Prior to this have built lua (dll, lib, compirer and interpreter). Downloaded cffi-lua sources using MCVS 2022. Istalled Meson / Python etc

When trying ti build using meson / ninja a have got multiple issues, some of them I was able to resolve but not all. Please help.

c:\Users\79151\source\repos\cffi-lua\build>meson .. -Dlua_version=5.4 -Dlibffi=vendor
The Meson build system
Version: 1.0.0
Source dir: C:\Users\79151\source\repos\cffi-lua
Build dir: C:\Users\79151\source\repos\cffi-lua\build
Build type: native build
Project name: cffi-lua
Project version: 0.2.3
C++ compiler for the host machine: cl (msvc 19.34.31937 "��⨬������騩 ��������� Microsoft (R) C/C++ ���ᨨ 19.34.31937 ��� x64")
C++ linker for the host machine: link link 14.34.31937.0
Host machine cpu family: x86_64
Host machine cpu: x86_64
Compiler for C++ supports arguments -Wshadow: NO
Compiler for C++ supports arguments -Wold-style-cast: NO
Did not find pkg-config by name 'pkg-config'
Found Pkg-config: NO
Found CMake: C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.EXE (3.24.202208181)
Run-time dependency lua5.4 found: NO (tried pkgconfig and cmake)
Run-time dependency lua-5.4 found: NO (tried pkgconfig and cmake)
Run-time dependency lua54 found: NO (tried pkgconfig and cmake)
Run-time dependency lua found: YES 5.4.4
Library ffi found: YES
Library dl found: NO
Computing int of "LUA_VERSION_NUM" with dependency lua: 504
Library lua found: NO
Library lua5.4 found: NO
Library lua54 found: YES
Program lua54 found: YES (C:\Program Files\Lua54\lua54.EXE)
WARNING: You should add the boolean check kwarg to the run_command call.
It currently defaults to false,
but it will default to true in future releases of meson.
See also: mesonbuild/meson#9300
Build targets in project: 2
NOTICE: Future-deprecated features used:

  • 0.56.0: {'meson.build_root', 'meson.source_root'}

cffi-lua 0.2.3

User defined options
libffi : vendor
lua_version: 5.4

Found ninja-1.11.1 at "C:\Program Files\Meson\ninja.EXE"
WARNING: Running the setup command as meson [options] instead of meson setup [options] is ambiguous and deprecated.

c:\Users\79151\source\repos\cffi-lua\build>ninja all
[1/10] Compiling C++ object cffi.dll.p/src_ast.cc.obj
FAILED: cffi.dll.p/src_ast.cc.obj
"cl" "-Icffi.dll.p" "-I." "-I.." "-I..\deps\include" "/MD" "/nologo" "/showIncludes" "/utf-8" "/Zc:__cplusplus" "/W4" "/EHs-c-" "/GR-" "/std:c++14" "/permissive-" "/O2" "/Zi" "-DCFFI_LUA_DLL" "-DFFI_LITTLE_ENDIAN" "/Fdcffi.dll.p\src_ast.cc.pdb" /Focffi.dll.p/src_ast.cc.obj "/c" ../src/ast.cc
c:\Users\79151\source\repos\cffi-lua\src\lua.hh(23): fatal error C1083: Не удается открыть файл включение: lua.hpp: No such file or directory,
[4/10] Compiling C++ object cffi.dll.p/src_ffilib.cc.obj
FAILED: cffi.dll.p/src_ffilib.cc.obj
"cl" "-Icffi.dll.p" "-I." "-I.." "-I..\deps\include" "/MD" "/nologo" "/showIncludes" "/utf-8" "/Zc:__cplusplus" "/W4" "/EHs-c-" "/GR-" "/std:c++14" "/permissive-" "/O2" "/Zi" "-DCFFI_LUA_DLL" "-DFFI_LITTLE_ENDIAN" "/Fdcffi.dll.p\src_ffilib.cc.pdb" /Focffi.dll.p/src_ffilib.cc.obj "/c" ../src/ffilib.cc
c:\Users\79151\source\repos\cffi-lua\src\lua.hh(23): fatal error C1083: Не удается открыть файл включение: lua.hpp: No such file or directory,
[5/10] Compiling C++ object cffi.dll.p/src_lib.cc.obj
FAILED: cffi.dll.p/src_lib.cc.obj
"cl" "-Icffi.dll.p" "-I." "-I.." "-I..\deps\include" "/MD" "/nologo" "/showIncludes" "/utf-8" "/Zc:__cplusplus" "/W4" "/EHs-c-" "/GR-" "/std:c++14" "/permissive-" "/O2" "/Zi" "-DCFFI_LUA_DLL" "-DFFI_LITTLE_ENDIAN" "/Fdcffi.dll.p\src_lib.cc.pdb" /Focffi.dll.p/src_lib.cc.obj "/c" ../src/lib.cc
c:\Users\79151\source\repos\cffi-lua\src\lua.hh(23): fatal error C1083: Не удается открыть файл включение: lua.hpp: No such file or directory,
[6/10] Compiling C++ object cffi.dll.p/src_parser.cc.obj
FAILED: cffi.dll.p/src_parser.cc.obj
"cl" "-Icffi.dll.p" "-I." "-I.." "-I..\deps\include" "/MD" "/nologo" "/showIncludes" "/utf-8" "/Zc:__cplusplus" "/W4" "/EHs-c-" "/GR-" "/std:c++14" "/permissive-" "/O2" "/Zi" "-DCFFI_LUA_DLL" "-DFFI_LITTLE_ENDIAN" "/Fdcffi.dll.p\src_parser.cc.pdb" /Focffi.dll.p/src_parser.cc.obj "/c" ../src/parser.cc
c:\Users\79151\source\repos\cffi-lua\src\lua.hh(23): fatal error C1083: Не удается открыть файл включение: lua.hpp: No such file or directory,
[7/10] Compiling C++ object cffi.dll.p/src_main.cc.obj
FAILED: cffi.dll.p/src_main.cc.obj
"cl" "-Icffi.dll.p" "-I." "-I.." "-I..\deps\include" "/MD" "/nologo" "/showIncludes" "/utf-8" "/Zc:__cplusplus" "/W4" "/EHs-c-" "/GR-" "/std:c++14" "/permissive-" "/O2" "/Zi" "-DCFFI_LUA_DLL" "-DFFI_LITTLE_ENDIAN" "/Fdcffi.dll.p\src_main.cc.pdb" /Focffi.dll.p/src_main.cc.obj "/c" ../src/main.cc
c:\Users\79151\source\repos\cffi-lua\src\lua.hh(23): fatal error C1083: Не удается открыть файл включение: lua.hpp: No such file or directory,
[8/10] Compiling C++ object cffi.dll.p/src_ffi.cc.obj
FAILED: cffi.dll.p/src_ffi.cc.obj
"cl" "-Icffi.dll.p" "-I." "-I.." "-I..\deps\include" "/MD" "/nologo" "/showIncludes" "/utf-8" "/Zc:__cplusplus" "/W4" "/EHs-c-" "/GR-" "/std:c++14" "/permissive-" "/O2" "/Zi" "-DCFFI_LUA_DLL" "-DFFI_LITTLE_ENDIAN" "/Fdcffi.dll.p\src_ffi.cc.pdb" /Focffi.dll.p/src_ffi.cc.obj "/c" ../src/ffi.cc
c:\Users\79151\source\repos\cffi-lua\src\lua.hh(23): fatal error C1083: Не удается открыть файл включение: lua.hpp: No such file or directory,
ninja: build stopped: subcommand failed.

c:\Users\79151\source\repos\cffi-lua\build>

In the subdirectory deps I have lua and ffi libs that I was able to build somehow

18.01.2023 11:30

.
18.01.2023 11:30 ..
18.01.2023 11:29 32 256 ffi-8.dll
18.01.2023 11:29 8 140 ffi.lib
18.01.2023 11:35 include
18.01.2023 00:15 18 432 lua.exe
18.01.2023 00:06 299 520 lua54.dll
18.01.2023 00:06 30 278 lua54.lib
5 файлов 388 626 байт

c:\Users\79151\source\repos\cffi-lua\deps>

Parse constants like luajit-ffi

Hello !
Nice work !
While doing some tests with existing luajit-ffi files I noticed that cffi do not understand this declarations as constants like enums:

/* kind of structural variable: */
static const int GLP_CV=  1;  /* continuous variable */
static const int GLP_IV = 2;  /* integer variable */
static const int GLP_BV=  3;  /* binary variable */

Cheers !

Create a meson subproject wrap file for libffi

I was compiling libffi on windows and I wasn't able to compile it. After searching through some issues and pull requests I found out that there is a PR which adds meson build support to libffi. You may consider it adding to cffi-lua.

subprojects/libffi.wrap

I think this is more stable.

[wrap-git]
url = https://gitlab.freedesktop.org/gstreamer/meson-ports/libffi.git
revision = meson
depth = 1

[provide]
ffi = ffi_dep

Or add gitlab rebased version with latest libffi.

[wrap-git]
url = https://github.com/xclaesse/libffi.git
revision = meson-port
depth = 1

[provide]
ffi = ffi_dep

https://github.com/q66/cffi-lua/blob/master/meson.build#L78-L85

ffi_dep = subproject('libffi').get_variable('ffi_dep')

Defining NDEBUG macro causes ffi.sizeof struct to return 0

Short background: remade the build system to work in conjuction with the rest of my system that builds Lua modules for a game. The build system for this game defines the macro NDEBUG for release builds.

While testing a build of this module with the NDEBUG macro, it was noticed that ffi.sizeof("struct something") was returning 0 (with this struct definition being struct something { int value; };). It will correctly return 4 if this macro is not defined. The host is a Linux x86_64 machine and it was built using GCC 9 (version doesn't matter).

I don't know if you will want to fix this issue but I'll use it as a heads-up for the future.

ffi.h not found

Since I couldn't get luarocks install --local cffi-lua to work (see Issue 3), I tried:

luarocks unpack cffi-lua
cd cffi-lua/cffi-lua-0.1.1-1/cffi-lua
luarocks make --local cffi-lua-0.1.1-1.rockspec

and then get an error about ffi.h not being found (see full log below), despite me having libffi installed and ffi.h residing in /usr/lib64/libffi-3.2.1/include/ffi.h.

I'm this build on amd64 Gentoo Linux.

Here's the full build log:

%  luarocks make --local cffi-lua-0.1.1-1.rockspec
env \
        LUA="lua" CC="gcc" LD="gcc" \
        CFLAGS='-O2 -fPIC -I/usr/include -I/usr/include' \
        LDFLAGS='-L/usr/lib -lffi' \
        PREFIX="/home/me/.luarocks/lib/luarocks/rocks/cffi-lua/0.1.1-1" LIBDIR="/home/me/.luarocks/lib/luarocks/rocks/cffi-lua/0.1.1-1/lib" \
        ./luarocks/build.sh build

The Meson build system
Version: 0.50.1
Source dir: /home/me/test/lua/cffi-lua/cffi-lua-0.1.1-1/cffi-lua
Build dir: /home/me/test/lua/cffi-lua/cffi-lua-0.1.1-1/cffi-lua/build
Build type: native build
Project name: cffi-lua
Project version: 0.1.1
Appending CXXFLAGS from environment: '-O2 -fPIC -I/usr/include -I/usr/include'
Appending LDFLAGS from environment: '-L/usr/lib -lffi'
Native C++ compiler: g++ (gcc 8.2.0 "g++ (Gentoo 8.2.0-r6 p1.7) 8.2.0")
Build machine cpu family: x86_64
Build machine cpu: x86_64
Compiler for C++ supports arguments -Wshadow: YES
Compiler for C++ supports arguments -Wold-style-cast: YES
Compiler for C++ supports arguments -fvisibility=hidden: YES
Checking for size of "void *" : 8
Has header "endian.h" : YES
Library dl found: YES
Has header "ffi.h" with dependency not-found: NO
Has header "ffi/ffi.h" with dependency not-found: NO

meson.build:109:8: ERROR: Problem encountered: libffi header file not found

A full log can be found at /home/me/test/lua/cffi-lua/cffi-lua-0.1.1-1/cffi-lua/build/meson-logs/meson-log.txt

Error: Build error: Failed building.

MetaType __len not working correctly

I'm trying to duplicate the following code from luajit ffi

local cffi = require("cffi")
cffi.cdef[[
typedef struct { double x, y; } point_t;
]]

local point
local mt = {
  __add = function(a, b) return point(a.x+b.x, a.y+b.y) end,
  __len = function(a) return math.sqrt(a.x*a.x + a.y*a.y) end,
  __index = {
    area = function(a) return a.x*a.x + a.y*a.y end,
  },
}
point = cffi.metatype("point_t", mt)

local a = point(3, 4)
print(a.x, a.y)  --> 3  4
print(#a)        --> 5
print(a:area())  --> 25
local b = a + point(0.5, 8)
print(#b)        --> 12.5

Everything works with the exception of __len. when the code reaches print(#a) I get the error 'struct 0' is not callable.

__add and __index both work fine if I remove the code using __len Tried on macos and Windows.

Support metatable for ctype

It would be nice to have metatable support for ctypes themselves, as with the LuaJIT FFI:

local ffi = require('cffi')

ffi.cdef[[
typedef struct point {
    int x;
    int y;
} point_t;
]]

local mt = {
    __tostring = function (self)
        return string.format("Point<%d, %d>", self.x, self.y)
    end,
    __index = {
        from_array = function (arr)
            return ffi.new("point_t", arr[1], arr[2])
        end
    }
}

Point = ffi.metatype("point_t", mt)

print(Point(1, 2)) --> Point<1, 2>
print(Point.from_array({3, 4})) --> expected: Point<3, 4>, cffi-lua gives: 'ctype' is not indexable

This allows implementing static methods on the ctype, like alternate constructors, or utility functions namespaced under the ctype.

Parameterized pointer type regression

local ffi = jit and require('ffi') or require('cffi')

ffi.cdef[[
typedef struct point {
    int x;
    int y;
} point_t;
]]

print(ffi.typeof("point_t")) --> ctype<struct point>
print(ffi.typeof("point_t *")) --> ctype<struct point *>
print(ffi.typeof("$ *", ffi.typeof("point_t"))) --> expected: ctype<struct point *>, get: ctype<struct point>

I'm expecting a pointer type for the parametrized typeof ffi.typeof("$ *", ffi.typeof("point_t"), but am getting the underlying structure type.

Running off of 07b30b0.

`unsigned short int` throws an error

Hello 👋

So, I have a problem with defiining an unsigned short int.
In LuaJIT's ffi, defining unsigned short int does valid, but in cffi-lua, it throws an error.

local cffi = require 'cffi'

cffi.cdef[[
unsigned short int myInt; // <-- Error/Invalid 
unsigned int myOtherInt; // <-- Valid
]]

Switch build system to XMake?

Right now I can't install this via LuaRocks because Meson isn't installed on our systems. Furthermore, adding cffi-lua as a dependency makes Meson a transitive dependency for building my library.

I was wondering if it'd be possible to switch over to using xmake as the build system? It'll provide a number of advantages:

  • There's a LuaRocks plugin you can add as a build-time dependency that'll automatically install it if it's not available. This means that users don't need to install XMake themselves.
  • XMake's configuration is literally just plain Lua.
  • You can use XMake's package management to install libffi if it's not installed already.
  • XMake is cross-platform.

This means that all users need to install cffi-lua is some version of Lua, an appropriate C++ compiler, and either XMake or LuaRocks depending on how they're installing it.

Support `char [N]` assignment from string

local ffi = jit and require('ffi') or require('cffi')

ffi.cdef[[
struct foo {
    char str[4];
};
]]

local f = ffi.new("struct foo")

f.str = "abc" --> expected: no error, get: "invalid C type"
print(ffi.string(f.str)) --> abc

f.str = "abcd1234"
print(ffi.string(f.str)) --> abcd

Segmentation fault when assigning a Lua callback to a C struct

Hello,

thank you for this great work :)

I am trying to adapt an existing LuaJIT+ffi project such that it could run with Lua as well using the cffi package. Doing so I am stuck with the following use case. When assigning a Lua callback to a C struct I get a segfault. Yet it works with LuaJIT. Below is a minimal example:

local ffi = jit and require('ffi') or require('cffi')

ffi.cdef([[
struct structure {
        void (*callback)(void);
};
]])

local structure = ffi.new('struct structure')
structure.callback = function () end

The last line gives a segfault on Debian using Lua 5.4+cffi. What could be the reason?

Support passing struct by value

local ffi = jit and require('ffi') or require('cffi')

--[[
/* testlib.c */
/* gcc -shared testlib.c -o testlib.so */
#include <stdio.h>

struct foo {
    int a;
    int b;
};

void print_foo(struct foo x) {
    printf("foo<%d, %d>\n", x.a, x.b);
}

void print_const_foo(const struct foo x) {
    printf("foo<%d, %d>\n", x.a, x.b);
}
]]--

ffi.cdef[[
struct foo {
    int a;
    int b;
};

void print_foo(struct foo x);
void print_const_foo(const struct foo x);
]]

local testlib = ffi.load('./testlib.so')

local foo = ffi.new("struct foo", 1, 2)

testlib.print_foo(foo) --> expected: foo<1, 2>, get: cannot convert 'struct foo' to 'struct foo'
testlib.print_const_foo(foo) --> expected: foo<1, 2>, get: cannot convert 'struct foo' to 'struct foo'

Failing FFI example

Hi! Thanks for this lib. Here's some code that I'm porting that implements a ring buffer. It errors on cffi but not luajit/other pure lua ffi implementations:

-- Use of this source code is governed by the Apache 2.0 license; see COPYING.

-- Ring buffer for bytes

local test_ffi_lib = 'ffi' -- 'cffi' or 'ffi'

local ffi = require(test_ffi_lib)
local bit = require("bit32")

local band = bit.band

ffi.cdef [[
   typedef struct {
      uint32_t read_idx, write_idx;
      uint32_t size;
      uint8_t buf[?];
   } buffer_t;
]]

local function to_uint32(n)
   return ffi.new('uint32_t[1]', n)[0]
end

local function new(size)
   local ret = buffer_t(size)
   ret:init(size)
   return ret
end

local buffer = {}
buffer.__index = buffer

function buffer:init(size)
   assert(size ~= 0 and band(size, size - 1) == 0, "size not power of two")
   self.size = size
   return self
end

function buffer:reset()
   self.write_idx, self.read_idx = 0, 0
end

function buffer:is_empty()
   return self.write_idx == self.read_idx
end
function buffer:read_avail()
   return to_uint32(self.write_idx - self.read_idx)
end
function buffer:is_full()
   return self:read_avail() == self.size
end
function buffer:write_avail()
   return self.size - self:read_avail()
end

function buffer:write_pos()
   return band(self.write_idx, self.size - 1)
end
function buffer:rewrite_pos(offset)
   return band(self.read_idx + offset, self.size - 1)
end
function buffer:read_pos()
   return band(self.read_idx, self.size - 1)
end

function buffer:advance_write(count)
   self.write_idx = self.write_idx + count
end
function buffer:advance_read(count)
   self.read_idx = self.read_idx + count
end

function buffer:write(bytes, count)
   if count > self:write_avail() then error('write xrun') end
   local pos = self:write_pos()
   local count1 = math.min(self.size - pos, count)
   ffi.copy(self.buf + pos, bytes, count1)
   ffi.copy(self.buf, bytes + count1, count - count1)
   self:advance_write(count)
end

function buffer:rewrite(offset, bytes, count)
   if offset + count > self:read_avail() then error('rewrite xrun') end
   local pos = self:rewrite_pos(offset)
   local count1 = math.min(self.size - pos, count)
   ffi.copy(self.buf + pos, bytes, count1)
   ffi.copy(self.buf, bytes + count1, count - count1)
end

function buffer:read(bytes, count)
   if count > self:read_avail() then error('read xrun') end
   local pos = self:read_pos()
   local count1 = math.min(self.size - pos, count)
   ffi.copy(bytes, self.buf + pos, count1)
   ffi.copy(bytes + count1, self.buf, count - count1)
   self:advance_read(count)
end

function buffer:drop(count)
   if count > self:read_avail() then error('read xrun') end
   self:advance_read(count)
end

function buffer:peek()
   local pos = self:read_pos()
   return self.buf + pos, math.min(self:read_avail(), self.size - pos)
end

buffer_t = ffi.metatype("buffer_t", buffer)

local function selftest()
   print('selftest: lib.buffer')
   local function assert_throws(f, ...)
      local success, ret = pcall(f, ...)
      assert(not success, "expected failure but got "..tostring(ret))
   end
   local function assert_avail(b, readable, writable)
      assert(b:read_avail() == readable)
      assert(b:write_avail() == writable)
   end
   local function write_str(b, str)
      local scratch = ffi.new('uint8_t[?]', #str)
      ffi.copy(scratch, str, #str)
      b:write(scratch, #str)
   end
   local function read_str(b, count)
      local scratch = ffi.new('uint8_t[?]', count)
      b:read(scratch, count)
      return ffi.string(scratch, count)
   end

   assert_throws(new, 10)
   local b = new(16)
   assert_avail(b, 0, 16)
   for i = 1,10 do
      local s = '0123456789'
      write_str(b, s)
      assert_avail(b, #s, 16-#s)
      assert(read_str(b, #s) == s)
      assert_avail(b, 0, 16)
   end

   local ptr, avail = b:peek()
   assert(avail == 0)
   write_str(b, "foo")
   local ptr, avail = b:peek()
   assert(avail > 0)

   -- Test wrap of indices.
   local s = "overflow"
   b.read_idx = to_uint32(3 - #s)
   b.write_idx = b.read_idx
   assert_avail(b, 0, 16)
   write_str(b, s)
   assert_avail(b, #s, 16-#s)
   assert(read_str(b, #s) == s)
   assert_avail(b, 0, 16)

   print('selftest: ok')
end

return {
    new = new,
    selftest = selftest
}

With luajit's ffi or https://github.com/jmckaskill/luaffi I get the following:

$ lua
Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio
> buffer = require 'buffer'; buffer.selftest()
selftest: lib.buffer
selftest: ok
> 

But with cffi the selftest() causes the interpreter to abort

$ lua
Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio
> buffer = require 'buffer'; buffer.selftest()
selftest: lib.buffer
free(): invalid size
Aborted
$

get rid of malloc and abort usage

All allocations in the system should be done through Lua's allocator. Also, we should never abort, instead access to lua_State state should be ensured at all times in those contexts and a Lua error should be raised.

Support passing pointer for array argument

local ffi = jit and require('ffi') or require('cffi')

ffi.cdef[[
    int pipe(int fildes[2]);
]]

--[[
-- also:
local buf = ffi.new('int [2]')
local pipe_fds = ffi.cast('int *', buf)
]]--

local pipe_fds = ffi.new('int [2]')
ffi.C.pipe(pipe_fds) --> expected: no error, get: cannot convert 'int *' to 'int [2]'
print(pipe_fds[0]) --> 3
print(pipe_fds[1]) --> 4

It appears that cdata<T [N]> and cdata<T *> types cannot be passed as an argument to a function expecting T [N].

Problem with simple "typedef"

When copying from a LuaJit.FFI interface, in order to get the CFFI version working I had to remove simple typedefs like

typedef long type_t;

and use the long instead. This is the CFFI error msg I get with typedef declarations:

input:1: ';' expected near 'time_t'

Any hope this can be integrated with CFFI? (... or am I doing something wrong; couldn't find an example or test using it.)

Support struct array element assignment from dereferenced const pointer

local ffi = jit and require('ffi') or require('cffi')

ffi.cdef[[
typedef struct point {
    int x;
    int y;
} point_t;
]]

local points1 = ffi.new("point_t[4]")
local points2 = ffi.new("point_t[4]")

local cpoints2 = ffi.cast("const point_t *", points2)

print(points1[0].x, points1[0].y) --> 0 0

points2[0].x = 1
points2[0].y = 2

points1[0] = cpoints2[0] --> expected: no error, get: cannot convert 'struct point' to 'struct point'

print(points1[0].x, points1[0].y) --> 1 2

Support passing string to `const void *`

local ffi = jit and require('ffi') or require('cffi')

ffi.cdef[[
    //typedef intptr_t ssize_t;
    ssize_t write(int fd, const void *buf, size_t count);
]]

local s = "hello world\n"
ffi.C.write(1, s, #s) --> expected: no error, get: cannot convert 'string' to 'void const *'

The LuaJIT FFI will happily cast a string to a const void * (but not to void *, understandably), which is useful for interacting with C functions dealing with byte strings (e.g. file descriptor I/O, sockets, etc.). cffi-lua doesn't support this without an explicit cast ffi.cast('const void *', s).

Release version 0.2.0

The amount of fixes since last release has been massive, so it's time to spin a new one.

Current TODO

Structure element assignment by value through array or pointer

local ffi = jit and require('ffi') or require('cffi')

ffi.cdef[[
typedef struct point {
    int x;
    int y;
} point_t;
]]

local mt = {
    __tostring = function (self)
        return string.format("Point<%d, %d>", self.x, self.y)
    end,
}

Point = ffi.metatype("point_t", mt)

ffi.cdef[[
void *malloc(size_t size);
]]

local buf = ffi.C.malloc(ffi.sizeof(Point) * 32)
local points = ffi.cast(ffi.typeof("$ *", Point), buf)

points[0].x = 1
points[0].y = 2
print(points[0]) --> Point<1, 2>

print(Point(1, 2)) --> Point<1, 2>

points[0] = Point(1, 2) --> expected: no error, get: cannot convert 'struct point' to 'struct point'
print(points[0]) --> Point<1, 2>

Error occurs when assigning a structure array element by value through a pointer. Same error occurs for assignment through a fixed size array, e.g. local points = ffi.new("point_t [32]").

How much compatibility is wanted?

Hi there q66,

Sorry its me again.
I do not know how compatible you want to be with the luajit ffi, but here's a test code which gave me issues:

local cffi = require("cffi")
cffi.cdef[[

typedef uint8_t Uint8;
typedef uint32_t Uint32;

typedef struct Device
{
    int needed;
    Uint8 *buf;
    Uint32 len;
} __attribute__((packed)) Device;

enum
{
    SDL_PIXELFORMAT_YV12 =
        ((((Uint32)(((Uint8)(('Y'))))) << 0) | (((Uint32)(((Uint8)(('V'))))) << 8) | (((Uint32)(((Uint8)(('1'))))) << 16) | (((Uint32)(((Uint8)(('2'))))) << 24)),
    SDL_PIXELFORMAT_IYUV =
        ((((Uint32)(((Uint8)(('I'))))) << 0) | (((Uint32)(((Uint8)(('Y'))))) << 8) | (((Uint32)(((Uint8)(('U'))))) << 16) | (((Uint32)(((Uint8)(('V'))))) << 24)),
    SDL_PIXELFORMAT_YUY2 =
        ((((Uint32)(((Uint8)(('Y'))))) << 0) | (((Uint32)(((Uint8)(('U'))))) << 8) | (((Uint32)(((Uint8)(('Y'))))) << 16) | (((Uint32)(((Uint8)(('2'))))) << 24)),
    SDL_PIXELFORMAT_UYVY =
        ((((Uint32)(((Uint8)(('U'))))) << 0) | (((Uint32)(((Uint8)(('Y'))))) << 8) | (((Uint32)(((Uint8)(('V'))))) << 16) | (((Uint32)(((Uint8)(('Y'))))) << 24)),
    SDL_PIXELFORMAT_YVYU =
        ((((Uint32)(((Uint8)(('Y'))))) << 0) | (((Uint32)(((Uint8)(('V'))))) << 8) | (((Uint32)(((Uint8)(('Y'))))) << 16) | (((Uint32)(((Uint8)(('U'))))) << 24))
};

int printf(const char *fmt, ...);
]]
cffi.C.printf("Hello %s!\n", "world")

This code, ported from a luajit ffi code, gives me errors on lines 10 and 17.
I can probably fix that manually, just wanted to know if this is something you expect to happen or if it is really bugs you want reported.

Thanks,
Marcelo.

ensure no stack values with destructors are present in OOM scenarios

in the very rare case that lua OOMs and raises a panic case, we should ensure that no stack values (which could be managing heap pointers) with destructors are present, to avoid leaking memory or causing any state to go inconsistent

this specifically only affects places where lua APIs are called

Support struct array element assignment from table

local ffi = jit and require('ffi') or require('cffi')

ffi.cdef[[
typedef struct point {
    int x;
    int y;
} point_t;
]]

local points = ffi.new("point_t[4]")

points[0] = {1, 2} --> expected: no error, get: cannot convert 'table' to 'struct point'

print(points[0].x, points[0].y) --> 1 2

I don't actually use this one, but happened to stumble across it. I didn't realize the LuaJIT FFI allowed it.

Support passing string through `ffi.string()`

local ffi = jit and require('ffi') or require('cffi')

local s = "hello world"
print(ffi.string(s)) --> expected: "hello world", get: bad argument #1 to 'string' (cannot convert 'string' to 'char const *')

LuaJIT FFI allows passing a string argument through ffi.string().

Interaction between cffi and lgi causes crashes

Hi, please see the below code for demo.

-- Uncommenting the line below will introduce a crash in callback:free().
require("cffi")
local lgi = require("lgi")
local callback = require("cffi").cast("void (*)()", function() end)
print("Before free")
callback:free()
print("After free")

I'm using cffi from luarocks, lua 5.1, and lgi from Debian repo (unstable).

Issues building on Debian for armhf

Hi There,

I have built this one on an armhf environment, together with Lua 5.3.6.
All seems to build fine, but when I try to do:

local cffi = require("cffi")

I get an error message:

lua: error loading module 'cffi' from file '/usr/local/lib/lua/5.3/cffi.so':
        /usr/local/lib/lua/5.3/cffi.so: unexpected reloc type 0x03

The process I am following is:
. Extract lua5.3.6
. build lua with make linux && make install
. then build cffi using -Dlua_version=vendor (I have copied the relevant files to deps folder)

cffi.so builds with no error, but gives me the message above when I try to use it.

I have no idea of what can be the issue, though I have a feeling it might be something simple I am missing.
Any help would be much appreciated.

Thanks,
Marcelo.

env: ‘./luarocks/build.sh’: Permission denied

When I try:

luarocks install --local cffi-lua

I get:

Installing https://rocks.moonscript.org/cffi-lua-0.1.1-1.src.rock...
Using https://rocks.moonscript.org/cffi-lua-0.1.1-1.src.rock... switching to 'build' mode
env \
        LUA="lua" CC="gcc" LD="gcc" \
        CFLAGS='-O2 -fPIC -I/usr/include -I/usr/include' \
        LDFLAGS='-L/usr/lib -lffi' \
        PREFIX="/home/me/.luarocks/lib/luarocks/rocks/cffi-lua/0.1.1-1" LIBDIR="/home/me/.luarocks/lib/luarocks/rocks/cffi-lua/0.1.1-1/lib" \
        ./luarocks/build.sh build

env: ‘./luarocks/build.sh’: Permission denied

Error: Build error: Failed building.

Support redefining nested anonymous struct within anonymous struct

local ffi = jit and require('ffi') or require('cffi')

ffi.cdef[[
    typedef struct {
        struct {
            uint32_t a;
        } inner1;
    } foo_t;

    typedef struct {
        struct {
            uint32_t b;
        } inner2;
    } bar_t;
]] -- expected: no error, get: input:1: 'struct 0' redefined

print(ffi.new("foo_t")) --> cdata<struct 95>: 0x40e88a78
print(ffi.new("bar_t")) --> cdata<struct 100>: 0x40e88b40

cffi-lua raises an error when redefining a nested anonymous struct within an anonymous struct. This is problematic in a codebase where two typedef anonymous structures happen to share a nested anonymous structure by sheer coincidence.

Note, however, redefinition of the nested anonymous structure is OK if the parent structure is named:

ffi.cdef[[
    struct foo {
        struct {
            uint32_t a;
        } inner1;
    };

    struct bar {
        struct {
            uint32_t b;
        } inner2;
    };
]] 

Build with prebuilt Lua Version

I am trying to build with a pre-build Lua version. meson was not able to find my Lua version. I then defined a lua.pc file:

`
prefix=/path/to/my/lua
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/inc

Name: lua
Description: Lua programming language
Version: 5.3
Libs: -L${libdir} -llua
Cflags: -I${includedir}
`

I then get the following error:

Found pkg-config: C:\msys64\mingw32\bin/pkg-config.EXE (1.8.0)
Found CMake: C:\msys64\mingw32\bin/cmake.EXE (3.25.1)
Run-time dependency lua5.3 found: NO (tried pkgconfig and cmake)
Run-time dependency lua-5.3 found: NO (tried pkgconfig and cmake)
Run-time dependency lua53 found: NO (tried pkgconfig and cmake)
Run-time dependency lua found: YES 5.3
Run-time dependency libffi found: YES 3.4.4
Library dl found: NO
Computing int of "LUA_VERSION_NUM" with dependency lua: 503
Library lua found: NO
Library lua5.3 found: NO

../meson.build:144:8: ERROR: C++ shared or static library 'lua53' not found

the libdir already has lua53.dll file in there. After I renamed lua53.dll to lua.dll then that worked. But now it was not able to find the executable Lua.

So I made the deps subdirectory and put the lua53 executable and dll in there with all the include files in the deps/include subdirectory. Then I ran the command:

meson .. -Dlua_version=5.3 -Dlua_path=/path/to/cffi-lua-0.2.3/build/deps/lua.exe

that worked!

Now when I run ninja I get all fatal errors that it cannot find lua.hpp.

So I had to manually edit build.ninja to add the "-Ideps/include" term in the commands.
After that it worked.

help with libcurl

I tried to use libcurl with cffi.
It's fine in luajit. but with puc it give error
libc: Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x7ac9a706e0 in tid 27717 (lua), pid 27717 (lua)

the problem is when doing curl_callback.

Also without this line in luajit also give strange incomplete result. maybe it's important to redefine the built-in typedefs which cffi fail to compile.

typedef int64_t time_t;
typedef unsigned int size_t;
local curl = require("libcurl-ffi")
-- local curl = require("luajit-curl")
local ffi = require"ffi" or require"cffi"

local ch = curl.curl_easy_init()

function curl_callback(callfunc)
  return ffi.cast("curl_callback", function (ptr, size, nmemb, stream)
  	local bytes = size*nmemb
  	local dst = ffi.new("char[?]", size*nmemb)
  	ffi.copy(dst, ptr, size*nmemb)
  	callfunc(ffi.string(dst, size*nmemb))
  	return bytes
  end)
end
if (ch) then
	curl.curl_easy_setopt(ch, curl.CURLOPT_URL, "http://example.com")
	curl.curl_easy_setopt(ch, curl.CURLOPT_FOLLOWLOCATION, 1)

  local raw_body = {}
  local raw_header = {}

	local clb_write = curl_callback(function(s) table.insert(raw_body, s) end)
	local clb_header = curl_callback(function(s) table.insert(raw_header, s) end)

	curl.curl_easy_setopt(ch, curl.CURLOPT_WRITEFUNCTION, clb_write)
	curl.curl_easy_setopt(ch, curl.CURLOPT_HEADERFUNCTION, clb_header)
		
	local success, err = pcall(function()
		return curl.curl_easy_perform(ch)
	end)
	clb_write:free()
	clb_header:free()
	
	print(success, err)
	
	-- local result = curl.curl_easy_perform(ch)
	-- if (result ~= curl.CURLE_OK) then
		-- print("FAILURE:", ffi.string(curl.curl_easy_strerror(result)))
	-- end
	
	if #raw_header>0 then
	  print(table.concat(raw_header))
	end
	print("bodylen:", #raw_body)

	curl.curl_easy_cleanup(ch)
	
	print("final>")
end

test_curl.lua.txt
libcurl-ffi.lua.txt

Support additional C type serialization with `ffi.string()`

local ffi = jit and require('ffi') or require('cffi')

local buf = ffi.new("uint8_t [3]", {0x61, 0x62, 0x63})
local p = ffi.cast("const uint8_t *", buf)

print(ffi.string(buf, ffi.sizeof(buf))) --> expected: abc, get: bad argument #1 to 'string' (cannot convert 'unsigned char [3]' to 'string')
print(ffi.string(p, 3)) --> expected: abc, get: bad argument #1 to 'string' (cannot convert 'unsigned char const *' to 'string')

ffi.cdef[[
struct foo {
    uint8_t a;
};
]]

local s = ffi.new("struct foo", 0x61)
local p = ffi.cast("const struct foo *", buf)

print(ffi.string(s, ffi.sizeof(s))) --> expected: a, get: bad argument #1 to 'string' (cannot convert 'struct foo' to 'string')
print(ffi.string(p, 1)) --> expected: a, get: bad argument #1 to 'string' (cannot convert 'struct foo *' to 'string')

Anonymous enum definition regression

local ffi = jit and require('ffi') or require('cffi')

ffi.cdef[[
    enum {FOO = 1};
    enum {BAR = 2};
]]

ffi.cdef[[
    enum {QUX = 3};
]] -- expected: no error, get: input:1: 'enum 3' redefined

Introduced in a335870.

__new metamethod never called

local ffi = require("cffi")

local S = ffi.metatype("struct { int x; }", {
   __new = function(ct, x)
      error("__new Called")
      return ffi.new(ct, x or 0)
   end,
})

local s = S()

Expected is that this test case to raise an error if the library is to operate similar to LuaJIT and as described in semantics.md. However it returns without error.

This is the output on LuaJIT (with require("ffi"))

luajit: test.lua:5: __new called
stack traceback:
	[C]: in function 'error'
	test.lua:5: in function 'S'
	test.lua:10: in main chunk
	[C]: at 0x5facfc7a2cd0

Instructions to build with MSVC

Maybe this will save someone some headache

  1. Get python version 3 in PATH. I just happened to have 3.11, no issues
  2. Get meson. Docs don't specify the version but the project won't build with version <0.64.
    For this I used vcpkg from Git Bash:
    cd /c/vcpkg
    git pull
    ./bootstrap-vcpkg.sh
    # if you have one installed but it is old
    ./vcpkg remove vcpkg-tool-meson --recurse
    ./vcpkg install vcpkg-tool-meson
  3. Do not use libffi from vcpkg since it is a DLL not a static lib
  4. Make cffi/deps folder and put whatever the docs say you need to put there. I've put this tree there
    lua53.dll
    lua53.lib
    lua53.exe
    include\lauxlib.h
    include\lua.h
    include\luaconf.h
    include\lualib.h
    include\lua.hpp
  5. mkdir cffi/build
  6. Now open a developer command prompt from Visual Studio in this folder and do this for default buildtype (debugoptimized). Use your paths. Git is needed to grab libffi. --skip-subprojects is needed to not install it since it is a static lib.
    set PATH=C:\Work\Tools\Git\bin;%PATH%
    python c:\vcpkg\downloads\tools\meson-1.3.2-d646d3\meson.py setup .. -Dlua_version=vendor -Dlua_install_path=c:\Work\Tools\qlua\lib\lua\@0@\debug
    ninja all
    ninja test
    python c:\vcpkg\downloads\tools\meson-1.3.2-d646d3\meson.py install --skip-subprojects
  7. This got installed
    Installing cffi.dll to c:\Work\Tools\qlua\lib\lua\5.3\debug
    Installing cffi.lib to c:\Work\Tools\qlua\lib\lua\5.3\debug
    Installing cffi.pdb to c:\Work\Tools\qlua\lib\lua\5.3\debug
    
  8. For a release build do this instead:
    set PATH=C:\Work\Tools\Git\bin;%PATH%
    python c:\vcpkg\downloads\tools\meson-1.3.2-d646d3\meson.py setup .. -Dlua_version=vendor -Dlua_install_path=c:\Work\Tools\qlua\lib\lua\@0@ -Dbuildtype=release
    ninja all
    ninja test
    python c:\vcpkg\downloads\tools\meson-1.3.2-d646d3\meson.py install --tags runtime
  9. This will get installed Installing cffi.dll to c:\Work\Tools\qlua\lib\lua\5.3

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.