Modular extension of compilation array

Let me say that I am in this appeal:

main.c:

 #include <stdio.h>
 #include <stdlib.h>

 #include "header.h"

 int iCanProcess (char* gimmeSmthToProcess);

 int processingFunctionsCount = 0;
 int (*(*processingFunctions)) (char*) = NULL;

 int addProcessingFunction(int (*fct)(char*)) {
     processingFunctionsCount++;
     processingFunctions = realloc(processingFunctions, 
               sizeof(int (*)(char*))*ProcessingFunctionsCount);
   processingFunctions[processingFunctionsCount-1] = fct;
 }

 int main(int argc, char *argv[]) {
     char* dataToProcess = "I am some veeeery lenghty data";
     addProcessingFunction(iCanProcess);

     [ ... ] 

     for(unsigned int i = 0; i < processingFunctionsCount; i++) {
         processingFunctions[i](dataToProcess);
     }

     free(processingFunctions);
   return 0;
 }

 int iCanProcess (char* gimmeSmthToProcess) { ... }

somefile.c:

 #include "header.h"

 int aFunction(char* someDataToProcess) { ... }  

header.h:

  #ifndef HEADER_DEF
  #define HEADER_DEF

  extern int processingFunctionsCount;
  extern int (*(*processingFunctions)) (char*);

  int addProcessingFunction(int (*fct)(char*));

  #endif

Is there any way using macros or any other trick I can add aFunctionfunction pointers to the array processingFunctionswithout changing, main.cor header.hevery time I need to add one?

The problem is not to change the array, since it can be easily redistributed, but NOT to change the function main(): there should be a way that I can know about the file that is here, and compiled, and get the function prototype from outsidemain()

I was thinking about using a preprocessor trick like this , but didn't seem to find a suitable way to do this ...

(Side-note: , , . , ( , , ), . , . , "", , , "", . main.c , .)

(Side-note 2: ... , , , , . )

+4
2

( dll Windows) , .sos .dlls, , , N , i-

module.i.c

int function(char *parameter)
{
     // Do whatever you want here
     return THE_RETURN_VALUE;
}

.c , Linux , , linux POSIX, .

module.i.c script

#!/bin/bash

for i in {0..100};
do
    cat > module.$i.c <<EOT
#include <stdlib.h>

int
function(char *parameter)
{
    // Deal with parameter
    return $i;
}
EOT
done

Makefile,

CC = gcc
LDFLAGS =
CFLAGS = -Wall -Werror -g3 -O0
FUNCTIONS = $(patsubst %.c,%.so, $(wildcard *.*.c))

all: $(FUNCTIONS)
    $(CC) $(CFLAGS) $(LDFLAGS) main.c -o main -ldl

%.so: %.c
    $(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@

clean:
    @rm -fv *.so *.o main

, ( , , )

#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <dlfcn.h>

int
main(void)
{
    DIR *dir;
    struct dirent *entry;
    dir = opendir(".");
    if (dir == NULL)
        return -1;
    while ((entry = readdir(dir)) != NULL)
    {
        void *handle;
        char path[PATH_MAX];
        int (*function)(char *);
        if (strstr(entry->d_name, ".so") == NULL)
            continue;
        if (snprintf(path, sizeof(path), "./%s", entry->d_name) >= sizeof(path))
            continue;
        handle = dlopen(path, RTLD_LAZY);
        if (handle == NULL)
            continue; // Better: report the error with `dlerror()'
        function = (int (*)(char *)) dlsym(handle, "function");
        if (function != NULL)
            fprintf(stdout, "function: %d\n", function("example"));
        else
            fprintf(stderr, "symbol-not-found: %s\n", entry->d_name);
        dlclose(handle);
    }
    closedir(dir);
    return 0;
}

Windows , , , LoadLibrary() dlopen() dlsym() .

.

, ,

+3

C . - .

C.

, , , /* PROCESSOR */, - . Perl :

use strict;

sub emit_header_file {
  my $protos = shift;
  open(F, "> table_protos.h") || die $!;
  print F <<"END";
#ifndef TABLE_PROTOS_H
#define TABLE_PROTOS_H
void addAllProcessingFunctions(void);
void addProcessingFunction(int (*)(char *));
END
  foreach my $proto (@$protos) {
    print F "int $proto->[0](char *$proto->[1]);\n";
  }
print F "#endif\n";
  close F;
}

sub emit_code_file {
  my $protos = shift;
  open(F, "> table_builder.c") || die $!;
  print F <<"END";
#include "table_protos.h"
void addAllProcessingFunctions(void) {
END
  foreach my $proto (@$protos) {
    print F "  addProcessingFunction($proto->[0]);\n";
  }
  print F "}\n";
  close F;
}

sub main {
  my @protos;
  my $dir = $ARGV[0];
  opendir(DIR, $dir) || die $!;
  while (my $fn = readdir(DIR)) {
    next unless $fn =~ /\.c$/;
    local $/;
    open(F, "$dir/$fn") || die "$!: $fn";
    my $s = <F>;
    my @proto = $s =~ m|/\*\s*PROCESSOR\s*\*/\s*int\s*(\w+)\s*\(\s*char\s*\*\s*(\w+)\s*\)|;
    push @protos, \@proto if @proto;
    print STDERR "Failed to find proto in $fn\n" unless @proto;
    close(F);
  }
  closedir(DIR);
  @protos = sort { $a->[0] cmp $b->[0] } @protos;
  emit_header_file(\@protos);
  emit_code_file(\@protos);
}

main;

, foo :

/* p1.c */
#include "table_protos.h"

// This is a processor.

/* PROCESSOR */
int procA(char *s) {
  return 0;
}

/* p2.c */
#include "table_protos.h"

/*PROCESSOR*/ int procB (
    char * 
      string_to_parse)
{ return 0; }

p3.c . , .

perl grok.pl foo

table_protos.h:

#ifndef TABLE_PROTOS_H
#define TABLE_PROTOS_H
void addAllProcessingFunctions(void);
void addProcessingFunction(int (*)(char *));
int procA(char *s);
int procB(char *string_to_parse);
int procC(char *param);
#endif

table_builder.c:

#include "table_protos.h"
void addAllProcessingFunctions(void) {
  addProcessingFunction(procA);
  addProcessingFunction(procB);
  addProcessingFunction(procC);
}

#include .

, , addAllProcessingFunctions. , script.

+1

Source: https://habr.com/ru/post/1623613/


All Articles