-
Notifications
You must be signed in to change notification settings - Fork 0
Documentation: The general
cDetect is a tool to help you configure projects - if on a larger scale, or just a small project. Whatever it is, cDetect can help you find out details about the host that your code is being compiled on.
To help you understand the API better, I will walk you thru a basic tutorial to construct a simple configure program. For this case, we are going to have a small project, but it has a little problem. We don't know, if malloc.h
is located directly via <malloc.h>
or via <malloc/mallocc.h>
. Actually, the latter only seems to be the case on Apple...but we never know, so we want to make sure.
Let's start!
cDetect is very portable, as it can be placed basically everywhere you want. Its good practice though to copy the entire cdetect folder into your project. Let's assume the following project tree:
./
├── cdetect
│ ├── autoconf.c
│ ├── cdetect.c
│ └── chost.c
├── readme.md
└── test.c
test.c
contains our code for the test project. Obviously, we are missing a configure code. We have two options to work with this:
- We use the configure.sh/.bat scripts provided
- We have an entry in our readme.md file to tell the client to first compile our code.
- We provide a basic makefile to compile the configure code.
In the case of the Phoenix Engine, I have taken the second aporoach and embedded the compiling and configuring deep into the build process.
To now get started, we create a configure.c
file first - with the following content:
#include "cdetect/cdetect.c"
int main(int argc, char** argv) {
config_begin(); // 1
// 2
if(config_options(argc, argv)) {
config_header_check("malloc.h") // 3
|| config_header_check("malloc/malloc.h"); // 4
}
config_end(); // 5
}
- We initialize the configuration process here.
- We hand cDetect the command line switches that it needs to parse options and things alike.
- The first check is for
<malloc.h>
. - If the first check fails, then we check for
<malloc/malloc.h>
. - The configuration is over, and we write the result to
config.h
- which looks like this:
/* Autogenerated by cDetect 0.2.2 -- http://cdetect.sourceforge.net/ */
#ifndef CDETECT_INCLUDE_GUARD_CONFIG_H
#define CDETECT_INCLUDE_GUARD_CONFIG_H
#define CDETECT_HEADER_MALLOC_MALLOC_H 1
#endif /* CDETECT_INCLUDE_GUARD_CONFIG_H */
Now, within test.c, you can look if either CDETECT_HEADER_MALLOC_H
or CDETECT_HEADER_MALLOC_MALLOC_H
is defined, to include the right one!
You obviously can do quite a bunch of checks. These are as follows:
-
config_header_check( header )
- Checks for a given header.
-
config_function_check( function )
- Check for a given function in the standard libraries. (I.e. no special LDFLAGS)
- Example:
config_function_check("vsprintf");
-
config_function_check_library( function, library )
- Check for a function given in a function.
- Example:
config_function_check_library("pthread_create", "pthread");
-
config_type_check( type )
- Lookup a type and define, if it exists.
- Example:
config_type_check("long long");
-
config_type_check_header( type, header )
- Check if a type exists in a given header.
- Example:
config_type_check_header("uint16_t","inttypes.h");
-
config_tool_check( tool )
- Check for a tool.
- Example:
config_tool_check("php");
-
config_cpu()
- Returns a char*, that tells you what architecture this is running on.
-
config_kernel()
- Determines the kernel.
-
config_macro_define( macro, value )
- Defines a custom macro.
- Example:
config_macro_define("PROJECT_VERSION", "0.1");
-
config_tool_define( key, value )
- Defines the existence of a tool.
- AND creates a variable that can later be used when building files off templates - see the generation part later.
- Example 1:
config_tool_define("BISON","bison");
- Example 2:
config_tool_define("CFLAGS", "-O3 -g");
-
config_header_define( header )
- Defines a header, adding the right macro to the resulting config.h
- Example:
config_header_define("d0p/d0p.h");
-
config_build_register( from, to )
- When
config_end()
is called, these files are rendered - from the template, to the result. - Example:
config_build_register("Makefile.in", "Makefile");
- !Note: Multiple calls are possible.
- When
-
config_header_register( header )
- Specify the exact output for the header.
- Example:
config_header_register("php_config.h");
-
config_cache_register( file )
- Specify the place where the cache should be kept.
- Example:
config_cache_register(".cache");
- config_compile_source( source, cflags )
- Compiles a source and returns zero on failure and non-zero on success.
- An example would be to test compile to check for the exact usage of a function, using the given result to then define a fitting macro.
-
config_option_register( Long name, Short name, Standard, Default, Help )
- Register an option to the help screen. You can later obtain the value with
config_option_get( _name_ )
. - Standard is applied to the option when it is not supplied by the user.
-
Default is being set to the options value, if the user specifies it without argument. (i.e.
--foo
) - If Standard AND Default are set to
0
, then this option does not require an argument. - If Standard is not
0
, but Default is, then the option's argument is mandatory. - If Standart is
0
, but Default is not, then the option's argument is optional.
- Register an option to the help screen. You can later obtain the value with
-
config_option_register_group( group )
- Register a group to the help screen.
- Example:
config_option_register_group("cDetect Extra (cache/output control)");
-
config_work_directory_register( dir )
- All files generated during the process and such, will be stored there. Make sure the folder exists!
-
cdetect_bool_t config_equal( string 1, string 2 )
- Compares two strings and returns a bool.
- Returns either CDETECT_TRUE or CDETECT_FALSE.
- Example:
if(config_equal(config_option_get("enable-localjpeg"),"no") == CDETECT_TRUE) {...} else {...}
-
config_report( message )
- Print a message
-
config_report_bool( message, bool )
- Emit a "checking for $message... (yes/no)" message.
- Second parameter is either 0 (false) or 1 (true).
- Hint:
(int)CDETECT_TRUE
or(int)CDETECT_FALSE
- Example:
config_report_bool("OpenGL Framework",1);
-
config_report_string( message, string )
- Instead of a bool, report an actual message.
-
config_abort()
- Abort the configuration immediately.
-
config_copyright_notice( notice )
- Obvious. o.o
-
cdetect_bool_t cdetect_tool_exist( tool )
- Only checks if a tool exists - does not define it, but returns a bool.
- Example:
if(cdetect_tool_exist("pkg-config") == CDETECT_FALSE) { config_report("pkg-config not found but required!") && config_abort() }
-
cdetect_bool_t cdetect_file_exist( filename )
- Checks if a file is existing. Note, that this does NOT define any macro!
- Example (actually used in PHP):
if((int)cdetect_file_exist("/dev/arandom")) config_macro_define("HAVE_DEV_ARANDOM","1");
In some cases, you have ran into the issue that a library you desire to use is only available in Autotools. What a same, really! But what if you wish to port it to cDetect? You can - and further, you also can get some autotools-like functions.
Once you include "cdetect/autoconf.c", you will have the following API:
-
ac_register()
- Register the autoconf layer - that includes changing the macro format, and the output to config.h. Call
config_header_register()
AFTER this.
- Register the autoconf layer - that includes changing the macro format, and the output to config.h. Call
-
ac_prefix()
- Add a good amount of prefix variables to the list of defined variables/tools. If you then generate a makefile that has names like
@prefix@
in it, it will be replaced by the respective option.
- Add a good amount of prefix variables to the list of defined variables/tools. If you then generate a makefile that has names like
-
ac_init( name, version, bug report )
- Begin your header with the typical info you would give Autoconf.
-
ac_path_prog( name, program, default program )
- Find out if program is given in PATH, and if so define it as tool under name. If not found, the default program will be set as the value instead.
-
ac_prog_shell()
- Find out the current shell and define it as SHELL.
-
ac_prog_egrep()
- Determine grep -E or such.
-
ac_prog_ranlib()
- Find ranlib.
-
ac_prog_awk()
- Find awk.
-
ac_prog_install()
- Determine the
install
program.
- Determine the
-
ac_prog_ln_s()
- Determine the usage of
ln -s
and its existence.
- Determine the usage of
-
ac_path_python( expected version )
- Find python, and make sure it is the expected version.
-
ac_header_stdc()
- Check for the standard C header files.
-
ac_header_time()
- Check for the time.h file.
-
ac_header_stdbool()
- Look for stdbool.h, or if _Bool is defined.
-
ac_header_resolv()
- Find the resolv.h file and its dependencies.
-
ac_header_dirent()
- Find the correct dir(...).h file.
-
ac_header_stat()
- Find the stat.h header.
-
ac_header_mmap_anonymous()
- Find the map.h file, and pick up if
MAP_ANONYMOUS
is useable.
- Find the map.h file, and pick up if
-
ac_header_sys_wait()
- Find the wait.h file
-
ac_type_pid_t() / ac_type_uid_t() / ac_type_off_t() / ac_type_size_t()
- Find the pid_t/uid_t/off_t/size_t type, and the headers.
-
ac_func_alloca()
- Find the
alloca
function.
- Find the
-
ac_func_rand48()
- Find the
*rand48
function.
- Find the
-
ac_c_inline()
- Check for the
inline
keyword.
- Check for the
-
ac_c_bigendian()
- Determine endianess.
- Returns 0 on little endian, 1 on big endian.
-
ac_c_printf_a()
- Check if printf supports the %a formatting specifier.
After you work a lot on your project, you see that your file structure has grown, and you have randomly encountered that you needed to use GYP for your building - or Scons, whatever. But you notice that you are left without configuration, really. But you now have a solution.
Imagine you are working on extending the Chromium project with FeatureFoo. But FeatureFoo requires a little configuration. So what you could do within your FunctionFoo.gyp file could look like this:
{
"targets": [
{
"target_name": "libbar_configure",
"type": "executable",
"sources": [
"libbar/configure.c"
]
},{
"target_name": "FeatureFoo",
"type": "...", #Whatever it is, your choice
"requires": ["libbar_configure"],
"actions": [{
"action_name": "cDetect",
"command": ["libbar_configure", "--output=libbar/config.h", "--enable-baz"]
}],
"sources": [...]
}
]
}
As you notice, my GYP-fu is not good... ;). But if you use it, you will notice what I was meaning to do - and this is pretty general:
- Compile the configure code.
- Make your actual target depend on the existence of this.
- Add a pre-build rule to run the program BEFORE building.
- Build your target, now with a config.h within!
This here, is just a fork and a contribution to the project that I originaly found on SourceForge, while I was in need for having configuration abilities on the go inside my current build system. The developer has helped me out a lot with understanding how this works and such! You should also check out his other projects as well. He has a nice article about predefined compiler macros, that is very helpful for compile-time configuration!
Find him here: https://sourceforge.net/u/breese/profile/
This documentation is not complete yet, and everything is stuffed in one single page. Further and better examples will follow. For example, I will take apart my FLTK configure code to showcase many functions that cDetect offers.