This example shows how to generate a standalone C library from MATLAB code that reads a file from disk using the standard C functions fopen/fread/fclose. To call these C functions, the MATLAB code uses the 'coder.ceval' function.
There are no prerequisites for this example.
The following code will create a folder in your current working folder (pwd). The new folder will only contain the files that are relevant for this example. If you do not want to affect the current folder (or if you cannot generate files in this folder), you should change your working folder.
coderdemo_setup('coderdemo_readfile');
The readfile.m function takes a file name (or path) as input and returns a string containing the contents of the file.
type readfile
% y = readfile(filename) % Read file 'filename' and return a MATLAB string with the contents % of the file. Internally C functions fopen/fread are used to read % data from the file. function y = readfile(filename) %#codegen % The 'fprintf' function will not be compiled and instead passed % to the MATLAB runtime. If we choose to generate code for this example, % all calls to extrinsic functions are automatically eliminated. coder.extrinsic('fprintf'); % Put class and size constraints on function input. assert(isa(filename, 'char')); assert(size(filename, 1) == 1); assert(size(filename, 2) <= 1024); % Define a new opaque variable 'f' which will be of type 'FILE *' % in the generated C code initially with the value NULL. f = coder.opaque('FILE *', 'NULL'); % Call fopen(filename 'r'), but we need to convert the MATLAB % string into a C type string (which is the same string with the % NUL (\0) string terminator). f = coder.ceval('fopen', c_string(filename), c_string('r')); % Call fseek(f, 0, SEEK_END) to set file position to the end of % the file. coder.ceval('fseek', f, int32(0), coder.opaque('int', 'SEEK_END')); % We need to initialize the variable 'filelen' to the proper type % as custom C functions are not analyzed. filelen = int32(0); % Call ftell(f) which will return the length of the file in bytes % (as current file position is at the end of the file). filelen = coder.ceval('ftell', f); % Reset current file position coder.ceval('fseek', f, int32(0), coder.opaque('int', 'SEEK_SET')); % Initialize a buffer buffer = zeros(1,65536,'uint8'); % Remaining is the number of bytes to read (from the file) remaining = filelen; % Index is the current position to read into the buffer index = int32(1); while remaining > 0 % Buffer overflow? if remaining + index > size(buffer,2) fprintf('Attempt to read file which is bigger than internal buffer.\n'); fprintf('Current buffer size is %d bytes and file size is %d bytes.\n', size(buffer,2), filelen); break end % Read as much as possible from the file into internal buffer nread = coder.opaque('size_t'); nread = coder.ceval('fread', coder.ref(buffer(index)), int32(1), remaining, f); n = int32(0); n = coder.ceval('(int)',nread); if n == 0 % Nothing more to read break; end % Did something went wrong when reading? if n < 0 fprintf('Could not read from file: %d.\n', n); break; end % Update state variables remaining = remaining - n; index = index + n; end % Close file coder.ceval('fclose', f); y = char(buffer(1:index)); % Create a NUL terminated C string given a MATLAB string function y = c_string(s) y = [s 0];
The 'readfile' function uses the following functions: 'coder.opaque': to declare a variable in the generated code 'coder.extrinsic': to instruct 'codegen' not to generate code for the specified function but instead to dispatch it to MATLAB for execution 'coder.ceval': to call external C functions
Generate a MEX function using the 'codegen' command.
codegen readfile
Before generating C code, you should first test the MEX function in MATLAB to ensure that it is functionally equivalent to the original MATLAB code and that no run-time errors occur. By default, 'codegen' generates a MEX function named 'readfile_mex' in the current folder. This allows you to test the MATLAB code and MEX function and compare the results.
Call the generated MEX function and display the size of the returned string and its first 100 characters.
y = readfile_mex('readfile.m');
size(y)
y(1:100)
ans = 1 2719 ans = % y = readfile(filename) % Read file 'filename' and return a MATLAB string with the contents % of th
cfg = coder.config('lib'); cfg.CustomSourceCode = '#include <stdio.h>'; codegen -config cfg readfile
Using 'codegen' with the specified '-config cfg' option produces a standalone C library using the STDIO standard header file.
By default, the code generated for the library is in the folder codegen/lib/readfile/
The files are:
dir codegen/lib/readfile/
. readfile_emxAPI.h rtGetInf.c .. readfile_emxAPI.o rtGetInf.h buildInfo.mat readfile_emxutil.c rtGetInf.o char.c readfile_emxutil.h rtGetNaN.c char.h readfile_emxutil.o rtGetNaN.h char.o readfile_initialize.c rtGetNaN.o codeInfo.mat readfile_initialize.h rt_nonfinite.c examples readfile_initialize.o rt_nonfinite.h interface readfile_ref.rsp rt_nonfinite.o readfile.a readfile_rtw.mk rtw_proj.tmw readfile.c readfile_terminate.c rtwtypes.h readfile.h readfile_terminate.h readfile.o readfile_terminate.o readfile_emxAPI.c readfile_types.h
type codegen/lib/readfile/readfile.c
/* * File: readfile.c * * MATLAB Coder version : 3.2 * C/C++ source code generated on : 23-Jul-2016 04:33:29 */ /* Include Files */ #include "rt_nonfinite.h" #include "readfile.h" #include "readfile_emxutil.h" #include "char.h" /* Custom Source Code */ #include <stdio.h> /* Function Definitions */ /* * The 'fprintf' function will not be compiled and instead passed * to the MATLAB runtime. If we choose to generate code for this example, * all calls to extrinsic functions are automatically eliminated. * Arguments : const char filename_data[] * const int filename_size[2] * emxArray_char_T *y * Return Type : void */ void readfile(const char filename_data[], const int filename_size[2], emxArray_char_T *y) { int n; int filelen; char tmp_data[1025]; char cv0[2]; FILE * f; static const char cv1[2] = { 'r', '\x00' }; unsigned char buffer[65536]; int b_index; boolean_T exitg1; emxArray_uint8_T *b_buffer; size_t nread; /* y = readfile(filename) */ /* Read file 'filename' and return a MATLAB string with the contents */ /* of the file. Internally C functions fopen/fread are used to read */ /* data from the file. */ /* Put class and size constraints on function input. */ /* Define a new opaque variable 'f' which will be of type 'FILE *' */ /* in the generated C code initially with the value NULL. */ /* Call fopen(filename 'r'), but we need to convert the MATLAB */ /* string into a C type string (which is the same string with the */ /* NUL (\0) string terminator). */ /* Create a NUL terminated C string given a MATLAB string */ n = filename_size[1]; for (filelen = 0; filelen < n; filelen++) { tmp_data[filelen] = filename_data[filename_size[0] * filelen]; } tmp_data[filename_size[1]] = '\x00'; for (filelen = 0; filelen < 2; filelen++) { cv0[filelen] = cv1[filelen]; } f = fopen(&tmp_data[0], cv0); /* Call fseek(f, 0, SEEK_END) to set file position to the end of */ /* the file. */ fseek(f, 0, SEEK_END); /* We need to initialize the variable 'filelen' to the proper type */ /* as custom C functions are not analyzed. */ /* Call ftell(f) which will return the length of the file in bytes */ /* (as current file position is at the end of the file). */ filelen = ftell(f); /* Reset current file position */ fseek(f, 0, SEEK_SET); /* Initialize a buffer */ memset(&buffer[0], 0, sizeof(unsigned char) << 16); /* Remaining is the number of bytes to read (from the file) */ /* Index is the current position to read into the buffer */ b_index = 1; exitg1 = false; while ((!exitg1) && (filelen > 0)) { /* Buffer overflow? */ if (b_index > MAX_int32_T - filelen) { n = MAX_int32_T; } else { n = filelen + b_index; } if (n > 65536) { exitg1 = true; } else { /* Read as much as possible from the file into internal buffer */ nread = fread(&buffer[b_index - 1], 1, filelen, f); n = (int)(nread); if ((n == 0) || (n < 0)) { /* Nothing more to read */ exitg1 = true; } else { /* Did something went wrong when reading? */ /* Update state variables */ filelen -= n; if ((b_index < 0) && (n < MIN_int32_T - b_index)) { b_index = MIN_int32_T; } else if ((b_index > 0) && (n > MAX_int32_T - b_index)) { b_index = MAX_int32_T; } else { b_index += n; } } } } emxInit_uint8_T(&b_buffer, 2); /* Close file */ fclose(f); filelen = b_buffer->size[0] * b_buffer->size[1]; b_buffer->size[0] = 1; b_buffer->size[1] = b_index; emxEnsureCapacity((emxArray__common *)b_buffer, filelen, (int)sizeof(unsigned char)); for (filelen = 0; filelen < b_index; filelen++) { b_buffer->data[b_buffer->size[0] * filelen] = buffer[filelen]; } b_char(b_buffer, y); emxFree_uint8_T(&b_buffer); } /* * File trailer for readfile.c * * [EOF] */
Remove files and return to original folder
cleanup