I am having issues where Zig is translating C code into “@compileError(“unable to resolve function type clang.TypeClass.MacroQualified”)” problem is, on other systems it translates fine (Linux/MacOS). A set of core functions are like this and would require me wrap just about every function into an object file which defeats the purpose of wanting to use Zig in this context.
Right now this is what I use for the zig build-lib
:
..\zig-windows-x86_64-0.13.0\zig.exe build-lib ext.zig
-fno-omit-frame-pointer
-freference-trace
-funwind-tables
-fallow-shlib-undefined
-fno-strip
-dynamic
-target x86_64-windows-msvc
-I./build/php-8.4-non-zts-debug/include
-I./build/php-8.4-non-zts-debug/include/main
-I./build/php-8.4-non-zts-debug/include/Zend
-I./build/php-8.4-non-zts-debug/include/TSRM
-I./build/php-8.4-non-zts-debug/include/ext
-Dtarget=native
-D_DISABLE_DEPRECATED_WARNINGS
-D_WIN32=1
-DZEND_WIN32=1
-DPHP_WIN32=1
-D_USRDLL
-DPHP8DLLTS_EXPORTS
-DPHP_EXPORTS
-DLIBZEND_EXPORTS
-DTSRM_EXPORTS
-DSAPI_EXPORTS
-DCOMPILE_DL_EXT
-D_WINDOWS
-D_MBCS
-D_USE_MATH_DEFINES
-DPHP_SIMD_SCALE=SSE2
-DFD_SETSIZE=256
-DNDEBUG
-DNDebug
-DCOMPILE_DL_EXT2
-DEXT2_EXPORTS=1
-D__zig__
-D_M_X64
-D_AMD64_
-D_WIN32_WINNT=0x0A00
-D__STDC_LIMIT_MACROS
-D_CRT_SECURE_NO_WARNINGS
-DO_CREAT=0x0100
-isystem C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.42.34433\\include
-isystem C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.22000.0\\ucrt
-isystem C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.22000.0\\shared
-isystem C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.22000.0\\um
-L C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.42.34433\\lib\\x64
-L C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.22000.0\\ucrt\\x64
-L C:\projects\zig-php-ext\build\php-8.4-non-zts-debug\lib\
-L C:\\projects\\zig-php-ext\\build\\php-8.4-non-zts-debug\\lib
-lc
--verbose-link
-lkernel32
-lole32
-luser32
-ladvapi32
-lshell32
-lws2_32
-lDnsapi
-lpsapi
-lbcrypt
-lphp8
-lucrt
-O Debug
-fPIC
-I.
-cflags
-fms-extensions
-mdefault-callconv=cdecl
-- wrapper.o
The result in my cimport.zig
is the following on Windows:
pub const _emalloc = @compileError("unable to resolve function type clang.TypeClass.MacroQualified");
// ./build/php-8.4-non-zts-debug/include/Zend/zend_alloc.h:67:53
pub extern fn _safe_emalloc(nmemb: usize, size: usize, offset: usize) ?*anyopaque;
pub extern fn _safe_malloc(nmemb: usize, size: usize, offset: usize) ?*anyopaque;
pub extern fn _efree(ptr: ?*anyopaque) void;
pub const _ecalloc = @compileError("unable to resolve function type clang.TypeClass.MacroQualified");
// ./build/php-8.4-non-zts-debug/include/Zend/zend_alloc.h:71:53
pub const _erealloc = @compileError("unable to resolve function type clang.TypeClass.MacroQualified");
// ./build/php-8.4-non-zts-debug/include/Zend/zend_alloc.h:72:31
pub const _erealloc2 = @compileError("unable to resolve function type clang.TypeClass.MacroQualified");
// ./build/php-8.4-non-zts-debug/include/Zend/zend_alloc.h:73:31
This _emalloc
is a core issue not being defined. On macOS I get:
pub extern fn _emalloc(size: usize, __zend_filename: [*c]const u8, __zend_lineno: u32, __zend_orig_filename: [*c]const u8, __zend_orig_lineno: u32) ?*anyopaque;
pub extern fn _safe_emalloc(nmemb: usize, size: usize, offset: usize, __zend_filename: [*c]const u8, __zend_lineno: u32, __zend_orig_filename: [*c]const u8, __zend_orig_lineno: u32) ?*anyopaque;
pub extern fn _safe_malloc(nmemb: usize, size: usize, offset: usize) ?*anyopaque;
pub extern fn _efree(ptr: ?*anyopaque, __zend_filename: [*c]const u8, __zend_lineno: u32, __zend_orig_filename: [*c]const u8, __zend_orig_lineno: u32) void;
pub extern fn _ecalloc(nmemb: usize, size: usize, __zend_filename: [*c]const u8, __zend_lineno: u32, __zend_orig_filename: [*c]const u8, __zend_orig_lineno: u32) ?*anyopaque;
pub extern fn _erealloc(ptr: ?*anyopaque, size: usize, __zend_filename: [*c]const u8, __zend_lineno: u32, __zend_orig_filename: [*c]const u8, __zend_orig_lineno: u32) ?*anyopaque;
pub extern fn _erealloc2(ptr: ?*anyopaque, size: usize, copy_size: usize, __zend_filename: [*c]const u8, __zend_lineno: u32, __zend_orig_filename: [*c]const u8, __zend_orig_lineno: u32) ?*anyopaque;
The general issue is that the source code I rely on seems to use MSVC with C++ compiler flags because max_align_t is missing from MSVC’s C compiler version. However Zig provides max_align_t via lib\include\__stddef_max_align_t.h
.
Here is a snippet of the file that defines _emalloc:
#ifndef ZEND_ALLOC_H
#define ZEND_ALLOC_H
#include <stdio.h>
#include "zend_types.h"
#include "../TSRM/TSRM.h"
#ifndef ZEND_MM_ALIGNMENT
# error "ZEND_MM_ALIGNMENT was not defined during configure"
#endif
#define ZEND_MM_ALIGNMENT_MASK ~(ZEND_MM_ALIGNMENT - 1)
#define ZEND_MM_ALIGNED_SIZE(size) (((size) + ZEND_MM_ALIGNMENT - 1) & ZEND_MM_ALIGNMENT_MASK)
#define ZEND_MM_ALIGNED_SIZE_EX(size, alignment) \
(((size) + ((alignment) - 1)) & ~((alignment) - 1))
typedef struct _zend_leak_info {
void *addr;
size_t size;
const char *filename;
const char *orig_filename;
uint32_t lineno;
uint32_t orig_lineno;
} zend_leak_info;
#if ZEND_DEBUG
typedef struct _zend_mm_debug_info {
size_t size;
const char *filename;
const char *orig_filename;
uint32_t lineno;
uint32_t orig_lineno;
} zend_mm_debug_info;
# define ZEND_MM_OVERHEAD ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info))
#else
# define ZEND_MM_OVERHEAD 0
#endif
BEGIN_EXTERN_C()
ZEND_API ZEND_ATTRIBUTE_MALLOC char* ZEND_FASTCALL zend_strndup(const char *s, size_t length);
ZEND_API ZEND_ATTRIBUTE_MALLOC void* ZEND_FASTCALL _emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE(1);
ZEND_API ZEND_ATTRIBUTE_MALLOC void* ZEND_FASTCALL _safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
ZEND_API ZEND_ATTRIBUTE_MALLOC void* ZEND_FASTCALL _safe_malloc(size_t nmemb, size_t size, size_t offset);
ZEND_API void ZEND_FASTCALL _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
ZEND_API ZEND_ATTRIBUTE_MALLOC void* ZEND_FASTCALL _ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE2(1,2);
ZEND_API void* ZEND_FASTCALL _erealloc(void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE(2);
ZEND_API void* ZEND_FASTCALL _erealloc2(void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE(2);
ZEND_API void* ZEND_FASTCALL _safe_erealloc(void *ptr, size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
ZEND_API void* ZEND_FASTCALL _safe_realloc(void *ptr, size_t nmemb, size_t size, size_t offset);
ZEND_API ZEND_ATTRIBUTE_MALLOC char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
ZEND_API ZEND_ATTRIBUTE_MALLOC char* ZEND_FASTCALL _estrndup(const char *s, size_t length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
ZEND_API size_t ZEND_FASTCALL _zend_mem_block_size(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
#include "zend_alloc_sizes.h"
/* _emalloc() & _efree() specialization */
#if !ZEND_DEBUG && defined(HAVE_BUILTIN_CONSTANT_P)
# define _ZEND_BIN_ALLOCATOR_DEF(_num, _size, _elements, _pages, x, y) \
ZEND_API ZEND_ATTRIBUTE_MALLOC void* ZEND_FASTCALL _emalloc_ ## _size(void);
ZEND_MM_BINS_INFO(_ZEND_BIN_ALLOCATOR_DEF, x, y)
ZEND_API ZEND_ATTRIBUTE_MALLOC void* ZEND_FASTCALL _emalloc_large(size_t size) ZEND_ATTRIBUTE_ALLOC_SIZE(1);
ZEND_API ZEND_ATTRIBUTE_MALLOC void* ZEND_FASTCALL _emalloc_huge(size_t size) ZEND_ATTRIBUTE_ALLOC_SIZE(1);
# define _ZEND_BIN_ALLOCATOR_SELECTOR_START(_num, _size, _elements, _pages, size, y) \
((size <= _size) ? _emalloc_ ## _size() :
# define _ZEND_BIN_ALLOCATOR_SELECTOR_END(_num, _size, _elements, _pages, size, y) \
)
# define ZEND_ALLOCATOR(size) \
ZEND_MM_BINS_INFO(_ZEND_BIN_ALLOCATOR_SELECTOR_START, size, y) \
((size <= ZEND_MM_MAX_LARGE_SIZE) ? _emalloc_large(size) : _emalloc_huge(size)) \
ZEND_MM_BINS_INFO(_ZEND_BIN_ALLOCATOR_SELECTOR_END, size, y)
# define _emalloc(size) \
(__builtin_constant_p(size) ? \
ZEND_ALLOCATOR(size) \
: \
_emalloc(size) \
)
There are two implementations one if there is debug turned on, another if not.
ZEND_API ZEND_ATTRIBUTE_MALLOC void* ZEND_FASTCALL _emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE(1);
# define _emalloc(size) \
(__builtin_constant_p(size) ? \
ZEND_ALLOCATOR(size) \
: \
_emalloc(size) \
)
Zig can seem to work and provide a correct version, IF I can expand the C macros first:
Debug Version
zig clang -E
-DPHP_WIN32
-D_M_X64
-D_AMD64_
-D_WIN32_WINNT=0x0A00
-D__STDC_LIMIT_MACROS
-D_CRT_SECURE_NO_WARNINGS
-DZEND_WIN32
-DZEND_DEBUG
-D__zig__
-DO_CREAT=0x0100
-DARCH_X86_64=1
-I"C:\projects\zig-windows-x86_64-0.13.0\lib\include"
-I"C:\projects\zig-php-ext\build\php-8.4-non-zts-debug\include"
-I"C:\projects\zig-php-ext\build\php-8.4-non-zts-debug\include\main"
-I"C:\projects\zig-php-ext\build\php-8.4-non-zts-debug\include\Zend"
-I"C:\projects\zig-php-ext\build\php-8.4-non-zts-debug\include\TSRM"
-I"C:\projects\zig-php-ext\build\php-8.4-non-zts-debug\include\win32"
-I"C:\projects\zig-php-ext\build\php-8.4-non-zts-debug\include\ext"
-I"C:\projects\zig-php-ext\build\php-8.4-non-zts-debug\include\sapi"
-isystem "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.42.34433\\include"
-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.22000.0\\ucrt"
-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.22000.0\\shared"
-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.22000.0\\um"
C:\projects\zig-php-ext\build\php-8.4-non-zts-debug\include\Zend\zend_alloc.h > out.c
Resulting _emalloc
__attribute__((dllimport)) __attribute__ ((__malloc__)) void* _emalloc(size_t size , const char *__zend_filename, const uint32_t __zend_lineno , const char *__zend_orig_filename, const uint32_t __zend_orig_lineno) __attribute__ ((alloc_size(1)));
Then toss that into Zig to translate.
zig translate-c
-target x86_64-windows-msvc
-fno-omit-frame-pointer
-freference-trace
-fallow-shlib-undefined
-DPHP_WIN32
-DZEND_DEBUG
-D_M_X64
-D_AMD64_
-DARCH_X86_64=1
-DWIN32_LEAN_AND_MEAN=1
-D_WIN32_WINNT=0x0A00
-D__STDC_LIMIT_MACROS
-D_CRT_SECURE_NO_WARNINGS
-DZEND_WIN32
-D__zig__
-Doff_t=__int64
-DO_CREAT=0x0100
-Dsocklen_t=int
-cflags
-fms-extensions
-- out.c > out.zig
Resulting Zig output is then correct:
pub extern fn _emalloc(size: usize, __zend_filename: [*c]const u8, __zend_lineno: u32, __zend_orig_filename: [*c]const u8, __zend_orig_lineno: u32) ?*anyopaque;
Its not just this single function it happens in so many other places and just confused on a possible fix. Linux and macOS work fine like I said, but I’ve been crazy trying to translate MSVC flags with Clang, through Zig and this is the last step to figure out as everything else is working. I am able to compile a .dll, load into php.exe, run functions without memory allocation required by the PHP runtime, but as soon as I do it crashes due to incorrect translations.