Git Product home page Git Product logo

module's Introduction

clibs/module

Macros to help define static module structure around C APIs.

Installation

$ clib install clibs/module --save

Usage

#include <clibs/module/require.h>
#include <clibs/module/module.h>
#include <clibs/module/def.h>

// module definition
module(your_module) {
  define(your_module, CLIB_MODULE);
};

// module initializer
int your_module_init(module(your_module) *exports) {
  return 0;
}

// module de-initializer
void your_module_deinit(module(your_module) *exports) {
}

// module exports
exports(your_module) {
  .init = your_module_init,
  .deinit = your_module_deinit,
};

Defining A Module

// the 'clib_module', 'clib_exports', etc macros
#include <clibs/module/module.h>

// defines 'module, exports, defaults, define, require' alias macros
#include <clibs/module/def.h>

enum channel_status {
  CHANNEL_STATUS_ERROR = -1,
  CHANNEL_STATUS_NONE = 0,
  CHANNEL_STATUS_OPEN = 1,
  CHANNEL_STATUS_CLOSED = 2,
};

// creates a module struct with the name 'channel'
// ie: `struct channel_clib_module { };`
module(channel) {
  // this initializes a few fields using the 'CLIB_MODULE'
  // prototype which is the expected prototype for the
  // 'clib_module_require()' function to work
  define(channel, CLIB_MODULE);

  // channel functions
  enum channel_status state;
  int (*open)();
  int (*close)();
  int (*send)(void *buf, size_t size);
  int (*recv)(void *buf, size_t size);
};

Exporting Module Symbols

// creates an exports interface with optional default values
exports(channel) {
  // the module initializer function called exactly once
  .init = channel_init,
  // the module deinitializer function called when free'd with
  // 'cilb_module_free' just before the 'free()' call
  .deinit = channel_deinit,
};

Requiring Module Symbols

module(channel) *channel = require(channel);

Example

Consider a simple logging module that defines and exports a mode property, and info(), debug(), and error() logging functions.

Below is a logger.h file that defines a logger module with a few exports.

logger.h:

#include <clibs/module/require.h>
#include <clibs/module/module.h>
#include <clibs/module/def.h>

enum logger_mode {
  LOGGER_NONE,
  LOGGER_INFO,
  LOGGER_ERROR,
  LOGGER_DEBUG,
};

// Module Type Interface
module(logger) {
  define(logger, CLIB_MODULE);

  enum logger_mode mode;
  void (*info)(char *);
  void (*debug)(char *);
  void (*error)(char *);
};

int
logger_init(module(logger) *exports);

void
logger_deinit(module(logger) *exports);

// Default Module Exports
exports(logger) {
  .mode = LOGGER_NONE,
  .init = logger_init,
  .deinit = logger_deinit,
};

The following logger.c file implements the logger module definition with a few explicit symbols init() and deinit(). These symbols can be set to 0 (NULL) for default behavior.

logger.c:

#include <stdio.h>
#include "logger.h"

int
logger_init(module(logger) *exports) {
  clib_module_init(logger, exports);
  exports->mode = LOGGER_NONE;
  exports->info = logger_info;
  exports->error = logger_error;
  exports->debug = logger_debug;
  return 0;
}

void
logger_deinit(module(logger) *exports) {
  clib_module_deinit(logger);
}

static inline void
logger_info(char *message) {
  if (require(logger)->mode >= LOGGER_INFO) {
    fprintf(stdout, " info: %s\n", message);
  }
}

static inline void
logger_error(char *message) {
  if (require(logger)->mode >= LOGGER_ERROR) {
    fprintf(stderr, "error: %s\n", message);
  }
}

static inline void
logger_debug(char *message) {
  if (require(logger)->mode >= LOGGER_DEBUG) {
    fprintf(stderr, "debug: %s\n", message);
  }
}

Below is a program consumes the logger module.

#include "logger.h"

int
main(void) {
  module(logger) *logger = require(logger);

  logger->mode = LOGGER_DEBUG;
  logger->info("hello");
  logger->error("oops");
  logger->debug("help");

  clib_module_free(logger);
  return 0;
}

API

clibs/module/module.h

clib_module(type)

Gets a reference to the module structure type.

// as a definition
clib_module(module) {
  clib_module_define(module, CLIB_MODULE);
};

// as type
clib_module(module) *exports = require(module);

Source:

#ifndef clib_module
#define clib_module(type) struct __##type##_clib_module
#endif

clib_module_exports(type)

Initializes the exports of a module and scopes its definition.

clib_module_exports(module) {
  clib_module_define(module, CLIB_MODULE);
};

Source:

#ifndef clib_module_exports
#define clib_module_exports(type)                                              \
  typedef clib_module(type) type##_t;                                          \
  static unsigned int __##type##_clib_module_init = 0;                         \
  static clib_module(type) *__##type##_clib_module;                            \
  static clib_module(type) __##type##_clib_module_exports =                    \

#endif

CLIB_MODULE_DEFAULT

The default module field initializer prototype.

clib_module_exports(module) {
  clib_module_defaults(module, CLIB_MODULE_DEFAULT)
}

Source:

#ifndef CLIB_MODULE_DEFAULT
#define CLIB_MODULE_DEFAULT(type)  \
  .name = ""#type,                 \
  .init = 0,                       \
  .deinit = 0                      \

#endif

clib_module_defaults(type, prototype)

Initializes defaults on a module type with a prototype.

clib_module_exports(module) {
  clib_module_defaults(module, CLIB_MODULE_DEFAULT)
};

Source:

#ifndef clib_module_defaults
#define clib_module_defaults(type, prototype) prototype(type)
#endif

clib_module_define(module, prototype)

Defines a module with a prototype's fields intended to be called inside the definition of a module structure.

clib_module(module) {
  clib_module_define(module, CLIB_MODULE);
  char *value;
  void *(function)(void *);
};

Custom prototypes can be used by defining a new macro

#define CUSTOM_PROTOTYPE      \
  CLIB_MODULE                 \
  void *(*function)(void *);  \

clib_module(module) {
  clib_module_define(module, CUSTOM_PROTOTYPE);
};

clib_exports(module) {
  .init = init, .deinit = 0,
};

Source:

#ifndef clib_module_define
#define clib_module_define(module, prototype) prototype(module)
#endif

clib_module_free(module)

Frees a module pointer and calls deinit() right before.

clib_module_free(module)

Source:

#ifndef clib_module_free
#define clib_module_free(module)                                               \
  if (0 != (module)) {                                                         \
    if (0 != (module)->deinit) {                                               \
      (module)->deinit((module));                                              \
    }                                                                          \
    free(module);                                                              \
  }

#endif

clibs/module/require.h

clib_module_require(name)

Returns an allocated pointer a module that should be free'd with clib_module_free().

clib_module(module) *mod = clib_module_require(module);

Source:

#define clib_module_require(name) ({                                           \
  if (0 == __##name##_clib_module_init || 0 == __##name##_clib_module) {       \
    __##name##_clib_module = malloc(sizeof(*__##name##_clib_module));          \
    clib_module_init(name, __##name##_clib_module);                            \
                                                                               \
    memset(                                                                    \
      __##name##_clib_module,                                                  \
      0,                                                                       \
      sizeof(__##name##_clib_module_exports));                                 \
                                                                               \
    memcpy(                                                                    \
      __##name##_clib_module,                                                  \
      &__##name##_clib_module_exports,                                         \
      sizeof(__##name##_clib_module_exports));                                 \
    __##name##_clib_module_init = 1;                                           \
                                                                               \
    if (0 != (__##name##_clib_module)->init) {                                 \
      if (0 != (__##name##_clib_module)->init((__##name##_clib_module))) {     \
        free(__##name##_clib_module);                                          \
        (__##name##_clib_module) = 0;                                          \
      }                                                                        \
    }                                                                          \
  }                                                                            \
                                                                               \
  (__##name##_clib_module);                                                    \
})

clibs/module/def.h

The def.h header file defines a set of alias macros for convenience.

module(type) {
  define(type, CLIB_MODULE);
  char *value;
};

exports(type) {
  defaults(type, CLIB_MODULE_DEFAULT),
  .value = "default value"
};

module(type) *exports = require(type);

Source:

#define defaults(...) clib_module_defaults(__VA_ARGS__)
#define require(...) clib_module_require(__VA_ARGS__)
#define exports(...) clib_module_exports(__VA_ARGS__)
#define module(...) clib_module(__VA_ARGS__)
#define define(...) clib_module_define(__VA_ARGS__)

Tests

Tests can be built and ran by running make test:

$ make test

Or with the clib build command:

$ clib build --force --test

Examples

Examples can be built and ran by running make example/{EXAMPLE}

$ make example/logger
$ make example/main

Or with the clib build command:

$ clib build --force -- example/logger
$ clib build --force -- example/main

License

MIT

module's People

Contributors

jwerle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

mightyhouseinc

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.