Skip to content

Add bin2obj rule, will be faster than bin2c#7103

Merged
waruqi merged 46 commits intodevfrom
bin2obj
Dec 7, 2025
Merged

Add bin2obj rule, will be faster than bin2c#7103
waruqi merged 46 commits intodevfrom
bin2obj

Conversation

@waruqi
Copy link
Member

@waruqi waruqi commented Dec 6, 2025

Compared to bin2c, it skips codegen and code compilation, directly generates the object file (coff, elf, macho), and then performs linking.

Therefore, it will be quite fast.

#7099 (comment)

Test results on macOS. xmake.ico is a 120MB file.

bin2obj

1.8s

ruki:bin2obj ruki$ xmake -r
[15%]: generating.bin2obj src/data.bin
[15%]: generating.bin2obj src/xmake.ico
[15%]: cache compiling.release src/main.c
[63%]: linking.release test
[100%]: build ok, spent 1.832s

bin2c

354.636s

ruki:bin2c ruki$ xmake -r
[1%]: generating.bin2c src/data.bin
[1%]: generating.bin2c src/xmake.ico
[23%]: cache compiling.release src/main.c
[47%]: linking.release test
[100%]: build ok, spent 354.636s

bin2obj - Binary to Object File Converter

Overview

The bin2obj rule converts binary files directly into object files that can be linked into your program, eliminating the need for compilation. This is more efficient than the traditional bin2c approach, as it avoids the compilation step and allows direct linking of binary data.

Features

  • Direct Linking: Convert binary files to object files without compilation
  • Cross-Platform: Supports COFF (Windows), ELF (Linux/Unix), and Mach-O (macOS/iOS) formats
  • Multiple Architectures: Supports x86, x86_64, ARM, ARM64, MIPS, RISC-V, PowerPC, SPARC, s390x, LoongArch, WebAssembly, and more
  • Automatic Format Detection: Automatically selects the appropriate object file format based on the target platform
  • Flexible Configuration: Configurable symbol prefixes, null terminator, and platform-specific options

Supported Formats

COFF (Common Object File Format)

  • Platforms: Windows, MinGW, MSYS, Cygwin
  • Extensions: .obj
  • Architectures: x86, x86_64, ARM, ARM64
  • Special Notes:
    • On i386, symbol names automatically get an extra underscore prefix (e.g., _binary_ becomes __binary_) to match the C compiler's behavior

ELF (Executable and Linkable Format)

  • Platforms: Linux, Android, FreeBSD, and other Unix-like systems
  • Extensions: .o
  • Architectures: x86, x86_64, ARM, ARM64, MIPS, MIPS64, RISC-V, PowerPC, SPARC, s390x, LoongArch, WebAssembly, SuperH, IA-64
  • Special Notes:
    • Supports both 32-bit and 64-bit ELF formats
    • Automatically includes .note.GNU-stack section to mark stack as non-executable

Mach-O (Mach Object)

  • Platforms: macOS, iOS, watchOS, tvOS
  • Extensions: .o
  • Architectures: x86_64, ARM64, i386
  • Special Notes:
    • Automatically configures platform, minimum version, and SDK version from Xcode toolchain
    • Supports iOS, macOS, tvOS, and watchOS platforms

Basic Usage

1. Add the Rule

Add the utils.bin2obj rule to your target:

target("myapp")
    set_kind("binary")
    add_rules("utils.bin2obj")
    add_files("src/*.c")
    add_files("assets/data.bin")

2. Use the Binary Data in C/C++

The binary file is converted to an object file with two symbols:

  • _binary_<basename>_start: Pointer to the start of the data
  • _binary_<basename>_end: Pointer to the end of the data

Example:

#include <stdio.h>
#include <stdint.h>

extern const uint8_t _binary_data_bin_start[];
extern const uint8_t _binary_data_bin_end[];

int main() {
    // Calculate size
    const uint32_t size = (uint32_t)(_binary_data_bin_end - _binary_data_bin_start);
    
    // Access the data
    printf("Data size: %u bytes\n", size);
    for (uint32_t i = 0; i < size; i++) {
        printf("%02x ", _binary_data_bin_start[i]);
    }
    return 0;
}

Configuration Options

Rule-Level Configuration

Configure options for all binary files in the target:

target("myapp")
    set_kind("binary")
    add_rules("utils.bin2obj", {
        format = "elf",              -- Force ELF format (optional, auto-detected by default)
        symbol_prefix = "_binary_",  -- Symbol prefix (default: "_binary_")
        zeroend = false              -- Append null terminator (default: false)
    })
    add_files("src/*.c")
    add_files("assets/*.bin")

File-Level Configuration

Configure options for individual files:

target("myapp")
    set_kind("binary")
    add_rules("utils.bin2obj")
    add_files("src/*.c")
    add_files("assets/data.bin", {zeroend = true})   -- Append null terminator
    add_files("assets/image.ico", {zeroend = false}) -- No null terminator

Custom File Extensions

By default, the rule processes .bin files. You can specify additional extensions:

target("myapp")
    set_kind("binary")
    add_rules("utils.bin2obj", {extensions = {".bin", ".ico", ".png"}})
    add_files("src/*.c")
    add_files("assets/*.bin")
    add_files("assets/*.ico")
    add_files("assets/*.png")

Advanced Usage

Manual Format Specification

Force a specific object file format:

target("myapp")
    set_kind("binary")
    add_rules("utils.bin2obj", {format = "coff"})  -- Force COFF format
    add_files("src/*.c")
    add_files("assets/data.bin")

Custom Symbol Prefix

Use a custom prefix for symbol names:

target("myapp")
    set_kind("binary")
    add_rules("utils.bin2obj", {symbol_prefix = "my_data_"})
    add_files("src/*.c")
    add_files("assets/data.bin")

Then in C code:

extern const uint8_t my_data_data_bin_start[];
extern const uint8_t my_data_data_bin_end[];

Null Terminator Control

Control whether a null terminator (\0) is appended to the data:

target("myapp")
    set_kind("binary")
    add_rules("utils.bin2obj")
    add_files("src/*.c")
    add_files("assets/text.txt", {zeroend = true})  -- Useful for text files
    add_files("assets/image.png", {zeroend = false}) -- Not needed for binary files

Symbol Naming

The symbol names are generated from the filename:

  • Filename: data.bin → Symbols: _binary_data_bin_start, _binary_data_bin_end
  • Filename: image.png → Symbols: _binary_image_png_start, _binary_image_png_end
  • Filename: config.json → Symbols: _binary_config_json_start, _binary_config_json_end

Dots (.) in the filename are replaced with underscores (_) in the symbol name.

Special Case: i386 on Windows

On i386 Windows (MinGW), the C compiler automatically adds an underscore prefix to external symbols. Therefore:

  • C code declares: _binary_data_bin_start
  • Actual symbol in object file: __binary_data_bin_start (two underscores)

The bin2obj rule automatically handles this by using __binary_ as the default prefix for i386.

Command-Line Usage

You can also use bin2obj directly from the command line:

xmake l utils.binary.bin2obj -i input.bin -o output.o -f elf -a x86_64

Command-Line Options

  • -i, --binarypath: Input binary file path (required)
  • -o, --outputpath: Output object file path (required)
  • -f, --format: Object file format (coff, elf, macho) (required)
  • -a, --arch: Target architecture (e.g., x86_64, arm64, i386) (required)
  • -p, --plat: Target platform (e.g., linux, macosx, windows) (required)
  • --symbol_prefix: Symbol prefix (default: _binary_)
  • --target_minver: Target minimum version for Mach-O (e.g., 10.0, 18.2)
  • --xcode_sdkver: Xcode SDK version for Mach-O (e.g., 10.0, 18.2)
  • --zeroend: Append a null terminator at the end of data

Examples

# Convert to COFF (Windows)
xmake l utils.binary.bin2obj -i data.bin -o data.obj -f coff -a x86_64 -p windows

# Convert to ELF (Linux)
xmake l utils.binary.bin2obj -i data.bin -o data.o -f elf -a x86_64 -p linux

# Convert to Mach-O (macOS)
xmake l utils.binary.bin2obj -i data.bin -o data.o -f macho -a x86_64 -p macosx

# With null terminator
xmake l utils.binary.bin2obj -i text.txt -o text.o -f elf -a x86_64 -p linux --zeroend

Supported Architectures

x86/x86_64

  • i386, x86 → 32-bit
  • x86_64, x64 → 64-bit

ARM

  • arm, armv7, armeabi-v7a, armv6, armv5 → 32-bit ARM
  • arm64, aarch64, arm64-v8a → 64-bit ARM

MIPS

  • mips, mipsel → 32-bit MIPS
  • mips64, mips64el → 64-bit MIPS

RISC-V

  • riscv → 32-bit RISC-V
  • riscv64 → 64-bit RISC-V

PowerPC

  • ppc, powerpc → 32-bit PowerPC
  • ppc64, powerpc64 → 64-bit PowerPC

SPARC

  • sparc → 32-bit SPARC
  • sparc64 → 64-bit SPARC

Others

  • s390x → IBM z/Architecture
  • loongarch, loongarch64, loong64 → LoongArch
  • wasm32 → WebAssembly 32-bit
  • wasm64 → WebAssembly 64-bit
  • sh, sh4, superh → SuperH
  • ia64, itanium → IA-64 (Itanium)

Complete Example

add_rules("mode.debug", "mode.release")

target("myapp")
    set_kind("binary")
    
    -- Add bin2obj rule with custom extensions
    add_rules("utils.bin2obj", {extensions = {".bin", ".ico", ".png"}})
    
    -- Source files
    add_files("src/*.c")
    
    -- Binary files with different configurations
    add_files("assets/data.bin", {zeroend = true})      -- Text-like data, needs null terminator
    add_files("assets/icon.ico", {zeroend = false})      -- Binary data, no null terminator
    add_files("assets/image.png", {zeroend = false})    -- Binary data, no null terminator
#include <stdio.h>
#include <stdint.h>

extern const uint8_t _binary_data_bin_start[];
extern const uint8_t _binary_data_bin_end[];

extern const uint8_t _binary_icon_ico_start[];
extern const uint8_t _binary_icon_ico_end[];

extern const uint8_t _binary_image_png_start[];
extern const uint8_t _binary_image_png_end[];

int main() {
    // Calculate sizes
    uint32_t data_size = (uint32_t)(_binary_data_bin_end - _binary_data_bin_start);
    uint32_t icon_size = (uint32_t)(_binary_icon_ico_end - _binary_icon_ico_start);
    uint32_t image_size = (uint32_t)(_binary_image_png_end - _binary_image_png_start);
    
    printf("Data size: %u bytes\n", data_size);
    printf("Icon size: %u bytes\n", icon_size);
    printf("Image size: %u bytes\n", image_size);
    
    // Use the binary data...
    
    return 0;
}

Comparison with bin2c

Feature bin2c bin2obj
Output C source file Object file
Compilation Required Not required
Build Speed Slower (compile step) Faster (direct linking)
File Size Larger (C source) Smaller (object file)
Use Case When you need C code When you just need to link data

Notes

  1. File Size Limit: The current implementation supports files up to 4GB (32-bit size limit for COFF format).

  2. Symbol Visibility: All symbols are exported as global symbols, making them accessible from other object files.

  3. Data Alignment: Data is aligned according to the target architecture's requirements (4 bytes for 32-bit, 8 bytes for 64-bit).

  4. Platform-Specific Behavior:

    • Windows/i386: Symbol names automatically get an extra underscore prefix
    • macOS/iOS: Automatically uses Xcode toolchain configuration for version info
    • Linux: Includes .note.GNU-stack section to prevent executable stack warnings
  5. Performance: Direct object file generation is faster than the bin2c approach, especially for large files, as it skips the compilation step.

Troubleshooting

Undefined Symbol Errors

If you get undefined symbol errors, check:

  • The symbol name matches the filename (dots replaced with underscores)
  • On i386 Windows, use __binary_ prefix (two underscores) instead of _binary_
  • The object file is included in the link command

Format Detection Issues

If the wrong format is detected, explicitly specify the format:

add_rules("utils.bin2obj", {format = "elf"})  -- Force ELF format

Large File Issues

For files larger than 4GB, consider splitting the file or using the bin2c approach instead.

See Also

@waruqi waruqi added this to the v3.0.6 milestone Dec 6, 2025
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @waruqi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant enhancement to Xmake by adding a bin2obj rule, designed to efficiently embed arbitrary binary data directly into compiled executables. Unlike the existing bin2c approach which involves an intermediate C source file and compilation, bin2obj directly generates platform-specific object files (e.g., COFF for Windows) from binary input. This streamlined process eliminates unnecessary steps, leading to faster build times when embedding resources. The change includes the core C implementation for COFF generation, Lua wrappers, and a new Xmake rule that intelligently selects the correct object file format based on the target system.

Highlights

  • New bin2obj Rule: Introduced a new rule to convert binary files directly into object files (COFF, ELF, Mach-O).
  • Performance Improvement: This method is faster than bin2c as it bypasses intermediate code generation and compilation, directly producing linkable object files.
  • COFF Format Support: The initial implementation provides C-level support for generating COFF object files.
  • Lua Integration: New Lua modules (private.utils.bin2obj and sandbox_utils.bin2coff) are added to expose this functionality and manage the conversion process.
  • Platform-Specific Format Detection: The utils.bin2obj rule automatically determines the appropriate object file format (COFF, ELF, Mach-O) based on the target platform.
  • Comprehensive Test Cases: A new test project (tests/projects/other/bin2obj) is included to validate the functionality of the bin2obj rule with sample binary and image files.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@waruqi waruqi changed the title Add bin2obj rule Add bin2obj rule, will be faster than bin2c Dec 6, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new bin2obj rule, which is a great performance improvement over bin2c. The implementation for the COFF format is well-done. However, the feature is incomplete as it lacks support for ELF and Mach-O formats, which will cause builds to fail on Linux and macOS. This is a critical issue that needs to be addressed. I've also provided several suggestions to improve the C implementation's robustness and maintainability, such as handling files larger than 4GB and using structs for binary data serialization to improve code clarity.

@waruqi waruqi merged commit 4e4b28e into dev Dec 7, 2025
65 of 66 checks passed
@waruqi waruqi deleted the bin2obj branch December 7, 2025 13:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant