Added a build script.

The build script was added to obtain the correct values of the
errno C preprocessor definitions. This way no matter what the platform
has defined them as, they will be correct in the libraries code.
This commit is contained in:
Myrddin Dundragon 2017-03-04 14:04:57 -05:00
parent 6e350daf26
commit 43abe9d95f
6 changed files with 433 additions and 1 deletions

View File

@ -7,18 +7,26 @@ license = ""
repository = "https://gitlab.com/CyberMages/pact.git"
documentation = ""
keywords = ["c", "libc", "binding", "ffi", "pact", "nostd"]
build = "build.rs"
[features]
default = []
use_std = ["scribe/use_std", "binding/use_std"]
use_std = ["scribe/use_std", "binding/use_std", "weave/use_std"]
rust_lib = []
no_mem_manip = []
weak = []
[build-dependencies.scribe]
git = "https://gitlab.com/CyberMages/scribe.git"
[dependencies.scribe]
git = "https://gitlab.com/CyberMages/scribe.git"
[dependencies.binding]
git = "https://gitlab.com/CyberMages/binding.git"
[dependencies.weave]
git = "https://gitlab.com/CyberMages/weave.git"

202
build.rs Normal file
View File

@ -0,0 +1,202 @@
#[macro_use]
extern crate scribe;
use std::env;
use std::ffi::OsString;
use std::path::PathBuf;
pub const BUILD_DIR: &'static str = "build";
pub const ERRNO_GENERATOR_FILENAME: &'static str = "errno.c";
pub const ERRNO_GENERATOR_OUTPUT_FILENAME: &'static str = "errno.gen";
pub const GENERATED_ERRNO_FILENAME: &'static str = "errno_values.rs";
fn determine_base_dir() -> PathBuf
{
// Get the cargo manifest directory.
match ::std::env::var_os("CARGO_MANIFEST_DIR")
{
Some(dir) =>
{
PathBuf::from(dir)
}
None =>
{
PathBuf::new()
}
}
}
fn determine_output_dir() -> PathBuf
{
let output_dir: PathBuf;
// Get the output directory for the build.
match ::std::env::var_os("OUT_DIR")
{
Some(dir) =>
{
output_dir = PathBuf::from(dir);
}
None =>
{
// Try to just get the current directory.
match env::current_dir()
{
Ok(dir) =>
{
output_dir = PathBuf::from(dir);
}
Err(error) =>
{
// Then just default to "".
warn!("{}", error);
output_dir = PathBuf::new();
}
}
}
}
output_dir
}
fn determine_build_dir() -> PathBuf
{
let mut build_dir: PathBuf;
build_dir = determine_base_dir();
build_dir.push(BUILD_DIR);
build_dir
}
fn determine_c_compiler() -> OsString
{
match ::std::env::var_os("CC")
{
Some(compiler) =>
{
OsString::from(compiler)
}
None =>
{
OsString::from("gcc")
}
}
}
fn build_output_file(filename: &str) -> PathBuf
{
let mut output_dir: PathBuf;
output_dir = determine_output_dir();
output_dir.push(filename);
output_dir
}
fn build_src_file(filename: &str) -> PathBuf
{
let mut build_dir: PathBuf;
build_dir = determine_build_dir();
build_dir.push(filename);
build_dir
}
fn compile(src_files: &[PathBuf], output_name: &str) -> PathBuf
{
let c_compiler: OsString;
let mut output_file: PathBuf;
let mut initial_command: ::std::process::Command;
let command: &mut ::std::process::Command;
let last_command: &mut ::std::process::Command;
let final_command: &mut ::std::process::Command;
c_compiler = determine_c_compiler();
output_file = build_output_file(output_name);
initial_command = ::std::process::Command::new(c_compiler);
command = initial_command.args(src_files);
last_command = command.arg("-o");
final_command = last_command.arg(output_file.clone());
match final_command.output()
{
Ok(output) =>
{
if output.status.success() == false
{
error!("{:?}", output);
}
}
Err(error) =>
{
error!("{}", error);
}
}
output_file
}
fn run(executable: PathBuf, args: &[PathBuf])
{
let mut initial_command: ::std::process::Command;
let final_command: &mut ::std::process::Command;
initial_command = ::std::process::Command::new(executable);
final_command = initial_command.args(args);
match final_command.output()
{
Ok(output) =>
{
if output.status.success() == false
{
error!("{:?}", output);
}
}
Err(error) =>
{
error!("{}", error);
}
}
}
fn compile_and_run(output_name: &str, src_files: &[PathBuf], args: &[PathBuf])
{
let executable: PathBuf;
executable = compile(src_files, output_name);
run(executable, args);
}
pub fn main()
{
let mut errno_file: PathBuf;
let mut gen_file: PathBuf;
let mut gen_errno_file: PathBuf;
errno_file = build_src_file(ERRNO_GENERATOR_FILENAME);
gen_file = build_output_file(ERRNO_GENERATOR_OUTPUT_FILENAME);
gen_errno_file = build_output_file(GENERATED_ERRNO_FILENAME);
compile_and_run(ERRNO_GENERATOR_OUTPUT_FILENAME,
&[errno_file], &[gen_errno_file]);
}

51
build/errno.c Normal file
View File

@ -0,0 +1,51 @@
#include <stdio.h>
#include <errno.h>
// Writes a public constant value to the desired file.
void write_constant(FILE* file, const char* name,
const char* type, const int val)
{
fprintf(file, "pub const %s: %s = %d;\n", name, type, val);
}
// Writes the header of the errno file.
void write_file_header(FILE* file)
{
fprintf(file, "// This was generated by a build script to obtain\n");
fprintf(file, "// the correct values of C preprocessor values to\n");
fprintf(file, "// be used as errno constant values.\n");
}
int main(int argc, char *argv[])
{
char* filename;
FILE* output_file;
// This requires a filename to be given for writing to.
if (argc == 2)
{
filename = argv[1];
}
else if (argc > 2 || argc < 2)
{
printf("\nThis program requires a filename be given.\n\n");
return 1;
}
// Open a file for writing.
output_file = fopen(filename, "w");
// Write the errno file header.
write_file_header(output_file);
// Write the errno constants we are trying to capture.
write_constant(output_file, "EDOM", "CInt", EDOM);
write_constant(output_file, "ERANGE", "CInt", ERANGE);
write_constant(output_file, "EILSEQ", "CInt", EILSEQ);
// Close the file.
fclose(output_file);
return 0;
}

167
src/c/errno.rs Normal file
View File

@ -0,0 +1,167 @@
use weave::Error;
use binding::CInt;
/// This signifies that there is no current error.
/// This can be used for clearing an error.
pub const NO_ERROR: CInt = 0;
/// Include the generated C error values.
include!(concat!(env!("OUT_DIR"), "/errno_values.rs"));
///
#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub enum CError
{
/// There is no Error.
None,
/// Some mathematical functions are only defined
/// for certain real values, which is called its domain,
/// for example the square root function is only defined for
/// non-negative numbers, therefore the sqrt function sets
/// errno to EDOM if called with a negative argument.
Domain,
/// The range of values that can be represented
/// with a variable is limited. For example, mathematical functions
/// such as pow can easily outbound the range representable by a
/// floating point variable, or functions such as strtod can
/// encounter sequences of digits longer than the range
/// representable values. In these cases, errno is set to ERANGE.
Range,
/// Multibyte character sequence may have a
/// restricted set of valid sequences. When a set of multibyte
/// characters is translated by functions such as mbrtowc,
/// errno is set to EILSEQ when an invalid sequence is encountered.
IllegalSequence,
/// There was a detected error, but it
/// is not one handled by CError.
Unhandled
}
impl CError
{
/// Returns if the given value is a handled CError.
pub fn is_handled_error(errno: i32) -> bool
{
let error: CError;
// Turn the error value into a CError and
// check if it is an Unhandled error.
error = CError::from(errno);
if error != CError::Unhandled
{
true
}
else
{
false
}
}
/// Check the last Error that was posted.
pub fn get_current_error() -> CError
{
CError::from(get_errno())
}
/// Set the current Error for the system.
pub fn set_current_error(error: CError)
{
set_errno(error as i32);
}
/// Clear the current Error.
pub fn clear()
{
CError::set_current_error(CError::None);
}
}
impl ::std::fmt::Debug for CError
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
::std::fmt::Display::fmt(self, f)
}
}
impl ::std::fmt::Display for CError
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
//write!(f, "{}", self.to_str())
write!(f, "{}", self.get_description())
}
}
impl From<i32> for CError
{
fn from(val: i32) -> CError
{
match val
{
NO_ERROR => { CError::None }
EDOM => { CError::Domain }
ERANGE => { CError::Range }
EILSEQ => { CError::IllegalSequence }
_ => { CError::Unhandled }
}
}
}
impl Error for CError
{
fn get_description(&self) -> &str
{
match *self
{
CError::None => { "There was no error" }
CError::Domain => { "Math argument out of domain of function" }
CError::Range => { "Math result not representable" }
CError::IllegalSequence => { "Illegal byte sequence" }
CError::Unhandled => { "Detected an Error not handled by CError" }
}
}
fn get_cause(&self) -> Option<&Error>
{
None
}
}
/// A helper function for getting the current error.
fn get_errno() -> i32
{
unsafe
{
*__errno_location() as i32
}
}
/// A helper function for setting the current error.
fn set_errno(errnum: i32)
{
unsafe
{
*__errno_location() = errnum as CInt;
}
}
// The function to get the errno memory location.
extern
{
fn __errno_location() -> *mut CInt;
}

View File

@ -3,10 +3,12 @@
//! this library is as up-to-date as it can be.
mod errno;
mod string;
mod time;
pub use self::errno::*;
pub use self::string::*;
pub use self::time::*;

View File

@ -18,6 +18,8 @@ extern crate scribe;
#[macro_use]
extern crate binding;
extern crate weave;
#[cfg(not(feature="rust_lib"))]