GNU/Linux >> Belajar Linux >  >> Linux

C/C++ dengan GCC:Menambahkan file sumber daya secara statis ke executable/library

Dengan imagemagick:

convert file.png data.h

Memberikan sesuatu seperti:

/*
  data.h (PNM).
*/
static unsigned char
  MagickImage[] =
  {
    0x50, 0x36, 0x0A, 0x23, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 
    0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4D, 0x50, 0x0A, 0x32, 0x37, 
    0x37, 0x20, 0x31, 0x36, 0x32, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0xFF, 0xFF, 
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 

....

Untuk kompatibilitas dengan kode lain, Anda dapat menggunakan fmemopen untuk mendapatkan FILE * "biasa". objek, atau sebagai alternatif std::stringstream untuk membuat iostream . std::stringstream tidak bagus untuk ini dan tentu saja Anda bisa menggunakan pointer di mana pun Anda bisa menggunakan iterator.

Jika Anda menggunakan ini dengan automake, jangan lupa untuk menyetel BUILT_SOURCES dengan benar.

Hal yang menyenangkan tentang melakukannya dengan cara ini adalah:

  1. Anda mengeluarkan teks, sehingga dapat berada dalam kontrol versi dan tambalan dengan wajar
  2. Ini portabel dan terdefinisi dengan baik di setiap platform

Anda dapat menyematkan file biner dalam file yang dapat dieksekusi menggunakan ld linker.Misalnya, jika Anda memiliki file foo.bar maka Anda dapat menyematkannya dalam executable dengan menambahkan perintah berikut ke ld

--format=binary foo.bar --format=default

Jika Anda memanggil ld melalui gcc maka Anda perlu menambahkan -Wl

-Wl,--format=binary -Wl,foo.bar -Wl,--format=default

Ini --format=binary memberi tahu linker bahwa file berikut adalah biner dan --format=default beralih kembali ke format input default (ini berguna jika Anda akan menentukan file input lainnya setelah foo.bar ).

Kemudian Anda dapat mengakses konten file Anda dari kode:

extern uint8_t data[]     asm("_binary_foo_bar_start");
extern uint8_t data_end[] asm("_binary_foo_bar_end");

Ada juga simbol bernama "_binary_foo_bar_size" . Saya pikir ini adalah tipe uintptr_t tapi saya tidak memeriksanya.


Perbarui Saya telah tumbuh untuk lebih memilih perakitan kontrol John Ripley .incbin penawaran solusi berbasis dan sekarang gunakan varian untuk itu.

Saya telah menggunakan objcopy (GNU binutils) untuk menautkan data biner dari file foo-data.bin ke bagian data yang dapat dieksekusi:

objcopy -B i386 -I binary -O elf32-i386 foo-data.bin foo-data.o

Ini memberi Anda foo-data.o file objek yang dapat Anda tautkan ke file yang dapat dieksekusi. Antarmuka C terlihat seperti

/** created from binary via objcopy */
extern uint8_t foo_data[]      asm("_binary_foo_data_bin_start");
extern uint8_t foo_data_size[] asm("_binary_foo_data_bin_size");
extern uint8_t foo_data_end[]  asm("_binary_foo_data_bin_end");

sehingga Anda dapat melakukan hal-hal seperti

for (uint8_t *byte=foo_data; byte<foo_data_end; ++byte) {
    transmit_single_byte(*byte);
}

atau

size_t foo_size = (size_t)((void *)foo_data_size);
void  *foo_copy = malloc(foo_size);
assert(foo_copy);
memcpy(foo_copy, foo_data, foo_size);

Jika arsitektur target Anda memiliki batasan khusus tentang tempat penyimpanan data konstan dan variabel, atau Anda ingin menyimpan data tersebut di .text segmen agar sesuai dengan jenis memori yang sama dengan kode program Anda, Anda dapat bermain dengan objcopy parameter lagi.


Linux
  1. Kirim dan Terima file dalam pemrograman soket di Linux dengan C/C++ (GCC/G++)

  2. Ulangi daftar file dengan spasi

  3. Bagaimana cara menambahkan file .so ke java.library.path di Linux

  1. Menautkan perpustakaan bersama dengan lib bersama lainnya di linux

  2. Pengelompokan regex cocok dengan pustaka regex C++ 11

  3. Bagaimana cara mendaftar dependensi pustaka statis c/c++?

  1. Cara Menambahkan Nomor Baris Ke File Teks Di Linux

  2. Kapan File yang Dapat Dieksekusi Tidak?

  3. File zip diperluas dengan garis miring terbalik di Linux, tanpa subdirektori