Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSVC support #35

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 32 additions & 8 deletions ctest.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,19 @@ CTEST_IMPL_DIAG_POP()
#define CTEST_IMPL_TEARDOWN_FPNAME(sname) CTEST_IMPL_NAME(sname##_teardown_ptr)

#define CTEST_IMPL_MAGIC (0xdeadbeef)
#ifdef __APPLE__
#if defined(_MSC_VER)
Copy link
Contributor

@aceckel aceckel Apr 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know the minimum version of MSVC that these changes work for? Can we check for it in the code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO there is no point in checking for a particular version since MSVC only started properly supporting C99 (think designated initializers and snprintf) quite recently (with VS 2013/2015).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so you are saying that, since the code assumes C99 features are present, any MSVC version that supports C99 will work. If we ever decide to support C89 compilation though, we may want to revisit this.

#pragma data_seg(push)
#pragma data_seg(".ctest$u")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the significance of $u here? I cannot find any documentation online about it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied blindly from #29. I agree that "subsection" is not really needed in this case, will remove upon rebase.

#pragma data_seg(pop)
#define CTEST_IMPL_SECTION __declspec(allocate(".ctest$u")) __declspec(align(1))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style nit: we can combine these __declspecs into one:

__declspec(allocate(".ctest$u"), align(1))

Apparently some compilers even will complain if you don't.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While works with MSVC, this comma-separated format is not documented AFAICT. MSDN article on __declspec only suggests that space-separated attributes are supported, and so does Clang test case on __declspec. I'd rather not change anything here at all, and silence corresponding Borland's warning/error (which is quite stupid if you ask me) if it comes to that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally reasonable, I'm fine with leaving it as-is.

#elif defined(__APPLE__)
#define CTEST_IMPL_SECTION __attribute__ ((used, section ("__DATA, .ctest"), aligned(1)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the gcc/clang definitions of CTEST_IMPL_SECTION, we use the attribute "used" to prevent an optimizing compiler from stripping the symbol from the resulting object file for never being referenced in the code. Does MSVC provide an analogous __declspec or #pragma for this sort of thing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find anything like used right away. Also don't recall whether I tested the optimized build or not, will need to get back to you on this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A simple and portable workaround for the symbol-stripping problem would be to remove static from the definitions. Compilers cannot strip non-static symbols even if they appear unused since another compilation unit may be externing them. This would also remove the need for the used attribute in the __GNUC__ case.

#else
#define CTEST_IMPL_SECTION __attribute__ ((used, section (".ctest"), aligned(1)))
#endif

#define CTEST_IMPL_STRUCT(sname, tname, tskip, tdata, tsetup, tteardown) \
static struct ctest CTEST_IMPL_TNAME(sname, tname) CTEST_IMPL_SECTION = { \
static struct ctest CTEST_IMPL_SECTION CTEST_IMPL_TNAME(sname, tname) = { \
.ssname=#sname, \
.ttname=#tname, \
.run = CTEST_IMPL_FNAME(sname, tname), \
Expand Down Expand Up @@ -187,11 +192,19 @@ void assert_dbl_far(double exp, double real, double tol, const char* caller, int
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>

#ifndef _WIN32
#include <sys/time.h>
#include <unistd.h>
#define CTEST_IMPL_ISATTY isatty
#else
#include <io.h>
#include <windows.h>
#define CTEST_IMPL_ISATTY _isatty
#endif

static size_t ctest_errorsize;
static char* ctest_errormsg;
#define MSG_SIZE 4096
Expand Down Expand Up @@ -405,11 +418,22 @@ static int suite_filter(struct ctest* t) {
}

static uint64_t getCurrentTime(void) {
uint64_t now64;
#ifndef _WIN32
struct timeval now;
gettimeofday(&now, NULL);
uint64_t now64 = (uint64_t) now.tv_sec;
now64 = (uint64_t) now.tv_sec;
now64 *= 1000000;
now64 += ((uint64_t) now.tv_usec);
#else
LARGE_INTEGER frequency;
LARGE_INTEGER counter;
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&counter);
now64 = counter.QuadPart;
now64 *= 1000000;
now64 /= frequency.QuadPart;
#endif
return now64;
}

Expand All @@ -425,7 +449,7 @@ static void color_print(const char* color, const char* text) {
static void sighandler(int signum)
{
char msg[128];
sprintf(msg, "[SIGNAL %d: %s]", signum, sys_siglist[signum]);
snprintf(msg, sizeof(msg), "[SIGNAL %d: %s]", signum, sys_siglist[signum]);
color_print(ANSI_BRED, msg);
fflush(stdout);

Expand Down Expand Up @@ -458,7 +482,7 @@ int ctest_main(int argc, const char *argv[])
#ifdef CTEST_NO_COLORS
color_output = 0;
#else
color_output = isatty(1);
color_output = CTEST_IMPL_ISATTY(1);
#endif
uint64_t t1 = getCurrentTime();

Expand Down Expand Up @@ -523,7 +547,7 @@ int ctest_main(int argc, const char *argv[])

const char* color = (num_fail) ? ANSI_BRED : ANSI_GREEN;
char results[80];
sprintf(results, "RESULTS: %d tests (%d ok, %d failed, %d skipped) ran in %" PRIu64 " ms", total, num_ok, num_fail, num_skip, (t2 - t1)/1000);
snprintf(results, sizeof(results), "RESULTS: %d tests (%d ok, %d failed, %d skipped) ran in %" PRIu64 " ms", total, num_ok, num_fail, num_skip, (t2 - t1)/1000);
color_print(color, results);
return num_fail;
}
Expand Down
2 changes: 1 addition & 1 deletion main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#define CTEST_MAIN

// uncomment lines below to enable/disable features. See README.md for details
#define CTEST_SEGFAULT
//#define CTEST_SEGFAULT
//#define CTEST_NO_COLORS
//#define CTEST_COLOR_OK

Expand Down
20 changes: 15 additions & 5 deletions mytests.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
#include <unistd.h>
#include <stdlib.h>

#ifndef _WIN32
#include <unistd.h>
#define MSLEEP(ms) usleep((ms) * 1000)
#else
#include <windows.h>
#define MSLEEP(ms) Sleep(ms)
#endif

#include "ctest.h"

// basic test without setup/teardown
CTEST(suite1, test1) {
usleep(2000);
MSLEEP(2);
}

// there are many different ASSERT macro's (see ctest.h)
Expand Down Expand Up @@ -54,7 +62,9 @@ CTEST2(memtest, test2) {
}


CTEST_DATA(fail) {};
CTEST_DATA(fail) {
int unused;
};

// Asserts can also be used in setup/teardown functions
CTEST_SETUP(fail) {
Expand Down Expand Up @@ -122,15 +132,15 @@ CTEST(ctest, test_assert_interval) {

CTEST(ctest, test_assert_null) {
ASSERT_NULL(NULL);
ASSERT_NULL((void*)0xdeadbeef);
ASSERT_NULL((void*)(intptr_t)0xdeadbeef);
}

CTEST(ctest, test_assert_not_null_const) {
ASSERT_NOT_NULL((const char*)"hallo");
}

CTEST(ctest, test_assert_not_null) {
ASSERT_NOT_NULL((void*)0xdeadbeef);
ASSERT_NOT_NULL((void*)(intptr_t)0xdeadbeef);
ASSERT_NOT_NULL(NULL);
}

Expand Down