I'm attempt to work with unit tests for meson, and am getting:
ϰ ninja
[4/4] Linking target test/crypto/crypto_tests.
FAILED: test/crypto/crypto_tests
clang++-6.0 -o test/crypto/crypto_tests 'test/crypto/test@crypto@@crypto_tests@exe/.._.._src_platform_encoding_Endian.c.o' 'test/crypto/test@crypto@@crypto_tests@exe/.._.._src_crypto_Sha1.c.o' 'test/crypto/test@crypto@@crypto_tests@exe/Sha1Tests.cpp.o' 'test/crypto/test@crypto@@crypto_tests@exe/.._.._subprojects_googletest-release-1.8.0_googletest_src_gtest-all.cc.o' 'test/crypto/test@crypto@@crypto_tests@exe/.._.._subprojects_googletest-release-1.8.0_googletest_src_gtest_main.cc.o' -Wl,--no-undefined -Wl,--as-needed -pthread
test/crypto/test@crypto@@crypto_tests@exe/Sha1Tests.cpp.o: In function `sha_one_hash_simple_Test::TestBody()':
/home/kfc/molten/magma/builddir/../test/crypto/Sha1Tests.cpp:46: undefined reference to `br_sha1_init(br_sha1_context*)'
/home/kfc/molten/magma/builddir/../test/crypto/Sha1Tests.cpp:47: undefined reference to `br_sha1_update(br_sha1_context*, void const*, unsigned long)'
/home/kfc/ecoan/molten/magma/builddir/../test/crypto/Sha1Tests.cpp:48: undefined reference to `br_sha1_out(br_sha1_context const*, void*)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
However I have defined those functions in Sha1.h:
#ifndef _CRYPTO_SHA1_H
#define _CRYPTO_SHA1_H
#include <stddef.h>
#include <string.h>
#include "../BuildSwitches.h"
#include "../types/BaseTypes.h"
/**
* Symbolic identifier for SHA-1.
*/
#define br_sha1_ID 2
/**
* SHA-1 output size (in bytes).
*/
#define br_sha1_SIZE 20
/**
* SHA-1 context.
*
* Fields are not supposed to be accessed by user code.
*/
typedef struct {
unsigned char buf[64];
UINT64 count;
UINT32 val[5];
} br_sha1_context;
/**
* SHA-1 context initialisation.
*
* This function initialises or resets a context for a new SHA-1
* computation.
*
* ctx: pointer to the context structure.
*/
void br_sha1_init(br_sha1_context *ctx);
/**
* Inject some data bytes in a running SHA-1 computation.
*
* The provided context is updated with some data bytes. If the number
* of bytes (`len`) is zero, then the data pointer (`data`) is ignored
* and may be `NULL`, and this function does nothing.
*
* ctx: pointer to the context structure.
* data: pointer to the injected data.
* len: injected data length (in bytes).
*/
void br_sha1_update(br_sha1_context *ctx, const void *data, size_t len);
/**
* Compute SHA-1 output.
*
* The SHA-1 output for the concatenation of all bytes injected in the
* provided context since the last initialisation or reset call, is
* computed and written in the buffer pointed to by `out`. The context
* itself is not modified, so extra bytes may be injected afterwards
* to continue that computation.
*
* ctx: pointer to the context structure.
* out: destination buffer for the hash output.
*/
void br_sha1_out(const br_sha1_context *ctx, void *out);
/**
* Save SHA-1 running state.
*
* The running state for SHA-1 (output of the last internal block
* processing) is written in the buffer pointed to by `out`. The
* number of bytes injected since the last initialisation or reset
* call is returned. The context is not modified.
*
* ctx: pointer to the context structure.
* out: destination buffer for the running state.
*
* returns: the injected total byte length.
*/
UINT64 br_sha1_state(const br_sha1_context *ctx, void *out);
/**
* Restore SHA-1 running state.
*
* The running state for SHA-1 is set to the provided values.
*
* ctx: pointer to the context structure.
* stb: source buffer for the running state.
* count: the injected total byte length.
*/
void br_sha1_set_state(br_sha1_context *ctx, const void *stb, UINT64 count);
void br_sha1_round(const unsigned char *buf, UINT32 *val);
extern const UINT32 br_sha1_IV[];
#endif // _CRYPTO_SHA1_H
These have the same definitions in Sha1.c:
#include "../platform/encoding/Endian.h"
#include "./Sha1.h"
#define F(B, C, D) ((((C) ^ (D)) & (B)) ^ (D))
#define G(B, C, D) ((B) ^ (C) ^ (D))
#define H(B, C, D) (((D) & (C)) | (((D) | (C)) & (B)))
#define I(B, C, D) G(B, C, D)
#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
#define K1 ((UINT32)0x5A827999)
#define K2 ((UINT32)0x6ED9EBA1)
#define K3 ((UINT32)0x8F1BBCDC)
#define K4 ((UINT32)0xCA62C1D6)
const UINT32 br_sha1_IV[5] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 };
void br_sha1_round(const unsigned char *buf, UINT32 *val) {
UINT32 m[80];
UINT32 a, b, c, d, e;
int i;
a = val[0];
b = val[1];
c = val[2];
d = val[3];
e = val[4];
br_range_dec32be(m, 16, buf);
for (i = 16; i < 80; i ++) {
UINT32 x = m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16];
m[i] = ROTL(x, 1);
}
for (i = 0; i < 20; i += 5) {
e += ROTL(a, 5) + F(b, c, d) + K1 + m[i + 0]; b = ROTL(b, 30);
d += ROTL(e, 5) + F(a, b, c) + K1 + m[i + 1]; a = ROTL(a, 30);
c += ROTL(d, 5) + F(e, a, b) + K1 + m[i + 2]; e = ROTL(e, 30);
b += ROTL(c, 5) + F(d, e, a) + K1 + m[i + 3]; d = ROTL(d, 30);
a += ROTL(b, 5) + F(c, d, e) + K1 + m[i + 4]; c = ROTL(c, 30);
}
for (i = 20; i < 40; i += 5) {
e += ROTL(a, 5) + G(b, c, d) + K2 + m[i + 0]; b = ROTL(b, 30);
d += ROTL(e, 5) + G(a, b, c) + K2 + m[i + 1]; a = ROTL(a, 30);
c += ROTL(d, 5) + G(e, a, b) + K2 + m[i + 2]; e = ROTL(e, 30);
b += ROTL(c, 5) + G(d, e, a) + K2 + m[i + 3]; d = ROTL(d, 30);
a += ROTL(b, 5) + G(c, d, e) + K2 + m[i + 4]; c = ROTL(c, 30);
}
for (i = 40; i < 60; i += 5) {
e += ROTL(a, 5) + H(b, c, d) + K3 + m[i + 0]; b = ROTL(b, 30);
d += ROTL(e, 5) + H(a, b, c) + K3 + m[i + 1]; a = ROTL(a, 30);
c += ROTL(d, 5) + H(e, a, b) + K3 + m[i + 2]; e = ROTL(e, 30);
b += ROTL(c, 5) + H(d, e, a) + K3 + m[i + 3]; d = ROTL(d, 30);
a += ROTL(b, 5) + H(c, d, e) + K3 + m[i + 4]; c = ROTL(c, 30);
}
for (i = 60; i < 80; i += 5) {
e += ROTL(a, 5) + I(b, c, d) + K4 + m[i + 0]; b = ROTL(b, 30);
d += ROTL(e, 5) + I(a, b, c) + K4 + m[i + 1]; a = ROTL(a, 30);
c += ROTL(d, 5) + I(e, a, b) + K4 + m[i + 2]; e = ROTL(e, 30);
b += ROTL(c, 5) + I(d, e, a) + K4 + m[i + 3]; d = ROTL(d, 30);
a += ROTL(b, 5) + I(c, d, e) + K4 + m[i + 4]; c = ROTL(c, 30);
}
val[0] += a;
val[1] += b;
val[2] += c;
val[3] += d;
val[4] += e;
}
void br_sha1_init(br_sha1_context *ctx) {
memcpy(ctx->val, br_sha1_IV, sizeof ctx->val);
ctx->count = 0;
}
void br_sha1_update(br_sha1_context *cc, const void *data, size_t len) {
const unsigned char *buf;
size_t ptr;
buf = (const unsigned char *) data;
ptr = (size_t)cc->count & 63;
while (len > 0) {
size_t clen;
clen = 64 - ptr;
if (clen > len) {
clen = len;
}
memcpy(cc->buf + ptr, buf, clen);
ptr += clen;
buf += clen;
len -= clen;
cc->count += (UINT64)clen;
if (ptr == 64) {
br_sha1_round(cc->buf, cc->val);
ptr = 0;
}
}
}
void br_sha1_out(const br_sha1_context *cc, void *dst) {
unsigned char buf[64];
UINT32 val[5];
size_t ptr;
ptr = (size_t)cc->count & 63;
memcpy(buf, cc->buf, ptr);
memcpy(val, cc->val, sizeof val);
buf[ptr ++] = 0x80;
if (ptr > 56) {
memset(buf + ptr, 0, 64 - ptr);
br_sha1_round(buf, val);
memset(buf, 0, 56);
} else {
memset(buf + ptr, 0, 56 - ptr);
}
br_enc64be(buf + 56, cc->count << 3);
br_sha1_round(buf, val);
br_range_enc32be(dst, val, 5);
}
UINT64 br_sha1_state(const br_sha1_context *cc, void *dst) {
br_range_enc32be(dst, cc->val, 5);
return cc->count;
}
void br_sha1_set_state(br_sha1_context *cc, const void *stb, UINT64 count) {
br_range_dec32be(cc->val, 5, stb);
cc->count = count;
}
I then have a test file that then attempts to test the SHA1 Functions:
#include <gtest/gtest.h>
#include "../../src/crypto/Sha1.h"
static size_t hextobin(unsigned char *dst, const char *src) {
size_t num;
unsigned acc;
int z;
num = 0;
z = 0;
acc = 0;
while (*src != 0) {
int c = *src ++;
if (c >= '0' && c <= '9') {
c -= '0';
} else if (c >= 'A' && c <= 'F') {
c -= ('A' - 10);
} else if (c >= 'a' && c <= 'f') {
c -= ('a' - 10);
} else {
continue;
}
if (z) {
*dst ++ = (acc << 4) + c;
num ++;
} else {
acc = c;
}
z = !z;
}
return num;
}
TEST(sha_one, hash_simple) {
unsigned char ref[br_sha1_SIZE];
hextobin(ref, (const char *) "a9993e364706816aba3e25717850c26c9cd0d89d");
unsigned char res[br_sha1_SIZE];
const char *data = (const char *)"abc";
br_sha1_context mc;
size_t n;
n = strlen(data);
br_sha1_init(&mc);
br_sha1_update(&mc, data, n);
br_sha1_out(&mc, res);
ASSERT_EQ(res, ref);
}
However, when using a meson.build file like:
crypto_srcs = [
'../../src/platform/encoding/Endian.c',
'../../src/crypto/Sha1.c',
'Sha1Tests.cpp',
]
e = executable('crypto_tests', sources : crypto_srcs, dependencies : gtest_dep)
test('crypto tests', e)
I'm getting the above error saying it can't find the reference to those functions (yet it seems to resolve the actual struct defined in that header file just fine? Which is extra confusing to me. So I then attempted to view the symbols on the object file itself to see if the functions were actually defined:
ϰ nm ./builddir/src/src@@magmatpm@sta/crypto_Sha1.c.o
0000000000000dc0 t br_enc32be
0000000000000ce0 t br_enc64be
U br_range_dec32be
U br_range_enc32be
0000000000000a80 T br_sha1_init
0000000000000000 R br_sha1_IV
0000000000000ba0 T br_sha1_out
0000000000000000 T br_sha1_round
0000000000000d70 T br_sha1_set_state
0000000000000d30 T br_sha1_state
0000000000000ac0 T br_sha1_update
U memcpy
U memset
Which shows the functions defined inside the object file. So I'm a bit confused on how I'm getting this error at all.