1
0
forked from 0ad/0ad

* Moved command-line options list from system.cfg into readme.txt. Updated the list to reflect reality. Removed -novbo option because you can use the .cfg file instead.

* Changed log files to trigger standards mode in Firefox (to be
consistent with other browsers), by making it valid HTML5. Changed the
font and some spacing.
 * Made CLogger default to ignoring messages if it hasn't been
initialised yet, instead of crashing.
 * Added leak reporting to the unit tests.
 * Renamed mods/_tests to mods/_test.xero, since it's only used by
Xeromyces and the other tests use mods/_test.otherstuff instead.
 * Fixed Atlas compilation on Windows.
 * Moved Atlas's DLL-loading code into a separate class, so it can be
shared.

This was SVN commit r4707.
This commit is contained in:
Ykkrosh 2006-12-20 03:09:21 +00:00
parent 64d56aadf8
commit 8b7d1fcfb3
17 changed files with 313 additions and 151 deletions

View File

@ -1,22 +1,3 @@
; COMMAND LINE OPTIONS:
;
; (note exact spelling of the actual switches, e.g. -nopbuffer, not -NOPBUFFER)
;
; -m=MAP load the file <MAP> (string) instead of the default test01.pmp
; -g=F set the gamma correction to <F> (floating point; 0.0 < F <= 1.0)
; -e show entity graph
; -v enable VSync, i.e. lock FPS to monitor refresh rate
; -novbo disable Vertex Buffer Objects; may solve graphics-related problems on older/buggy graphics cards
; -nopbuffer disable Pixel Buffers; may solve graphics-related problems on older/buggy graphics cards
; -f enable fixed frame timing; ?
; -s enable shadows
; -xres=N set desired screen X resolution to <N> (integer)
; -yres=N set desired screen Y resolution to <N> (integer)
; -conf NAME=VAL set config variable <NAME> (string) to <VAL> (string)
;
; Command-line switches override anything in config or profile files.
; Profile settings
; profile = default

View File

@ -0,0 +1 @@
Not a valid XML file.

View File

@ -0,0 +1 @@
Not a valid XML file.

View File

@ -1,10 +1,33 @@
BODY { background-color: #EEEEEE; font-family: "Tahoma"; font-size: 12pt; color: #000000}
body {
background-color: #eee;
font-family: sans-serif;
color: black;
}
P { background-color: #FFFFFF; font-family: "Tahoma"; font-size: 12pt; color: #000000;}
p.logo {
margin: 0;
padding: 0;
text-align: center;
}
P.error { background-color: #FFFFFF; font-family: "Tahoma"; font-size: 12pt; color: red}
p {
margin-top: 0.2em;
margin-bottom: 0.2em;
padding: 1px;
}
P.warning { background-color: #FFFFFF; font-family: "Tahoma"; font-size: 12pt; color: #0000FF}
h1 {
font-size: 1.3em;
}
H1 { background-color: #EEEEEE; font-family: "Tahoma"; font-size: 16pt; font-color: #000000 }
p {
background-color: white;
}
.error {
color: red;
}
.warning {
color: blue;
}

View File

@ -1,10 +1,18 @@
Last Update: 29th August 2004
This is the 0 A.D. readme file. Its content is somewhat limited, since it is primarily here to stop the system/ folder from disappearing from CVS now that all binaries are stored elsewhere. ;)
If all has gone well, there should be two binaries in this folder:
* ps_test.exe: This is a customised debug version of the build. It runs like crystallised treacle, but it does keep better track of memory. If it crashes or you otherwise encounter an issue, please post the two crashdump files that appear in your data/ directory as a bug report at http://bugs.wildfiregames.com, along with the date of your build, and we will be able to trace the crashdump to isolate the error, and hopefully fix it.
* ps.exe: Run this for a release version of the build. It's faster, but it won't generate an accurate crash dump. So if it crashes, we'll have a hard time isolating the source. For testing purposes, it's therefore best to run ps_test.
COMMAND LINE OPTIONS:
-autostart=MAP load the file 'MAP' instead of showing the main menu
-buildarchive ?
-conf:KEY=VALUE set a config value (overrides the contents of system.cfg)
-entgraph ?
-fixedframe enable fixed frame timing; ?
-g=F set the gamma correction to 'F' (default 1.0)
-listfiles ?
-profile=NAME ?
-quickstart load faster (disables audio and some system info logging)
-shadows enable shadows
-vsync enable VSync, i.e. lock FPS to monitor refresh rate
-xres=N set screen X resolution to 'N'
-yres=N set screen Y resolution to 'N'
-editor launch the Atlas scenario editor
-actorviewer when combined with -editor, launch the Actor Viewer tool

View File

@ -723,7 +723,7 @@ function setup_tests()
links = static_lib_names
tinsert(links, "test_3_gen")
extra_params = {
extra_files = { "test_root.cpp" },
extra_files = { "test_root.cpp", "test_setup.cpp" },
extra_links = links,
}
package_add_contents(source_root, {}, {}, extra_params)

View File

@ -1,24 +1,33 @@
#include "precompiled.h"
#include "CLogger.h"
#include "CConsole.h"
#include "ConfigDB.h"
#include "lib/lib.h"
#include "lib/path_util.h"
#include "lib/res/file/file.h"
#include <time.h>
#include <ostream>
CLogger* g_Logger = NULL;
// Set up a default logger that throws everything away, because that's
// better than crashing. (This is particularly useful for unit tests which
// don't care about any log output.)
struct BlackHoleStreamBuf : public std::streambuf
{
} blackHoleStreamBuf;
std::ostream blackHoleStream(&blackHoleStreamBuf);
CLogger nullLogger(&blackHoleStream, &blackHoleStream, false);
#include "CConsole.h"
using namespace std;
CLogger* g_Logger = &nullLogger;
const char* html_header0 =
"<!DOCTYPE HTML SYSTEM>\n"
"<!DOCTYPE HTML>\n" // HTML5 doctype - triggers standards mode in current browsers
// (The W3C validator doesn't like it - use
// http://hsivonen.iki.fi/validator/html5/ instead)
"<title>Pyrogenesis Log</title>\n"
"<link rel=\"stylesheet\" href=\"style.css\" type=\"text/css\">\n"
"<p align=\"center\"><img src=\"0adlogo.jpg\" alt=\"0 A.D.\"></p>\n"
"<p class=\"logo\"><img src=\"0adlogo.jpg\" alt=\"0 A.D.\"></p>\n"
"<h1>";
// (note that the html,head,body tags are optional)
@ -36,18 +45,21 @@ CLogger::CLogger()
(void)path_package_set_dir(&pp, N_path);
(void)path_package_append_file(&pp, "mainlog.html");
m_MainLog = new std::ofstream(pp.path, ofstream::out | ofstream::trunc);
m_MainLog = new std::ofstream(pp.path, std::ofstream::out | std::ofstream::trunc);
(void)path_package_append_file(&pp, "interestinglog.html");
m_InterestingLog = new std::ofstream(pp.path, ofstream::out | ofstream::trunc);
m_InterestingLog = new std::ofstream(pp.path, std::ofstream::out | std::ofstream::trunc);
m_OwnsStreams = true;
Init();
}
CLogger::CLogger(std::ostream* mainLog, std::ostream* interestingLog)
CLogger::CLogger(std::ostream* mainLog, std::ostream* interestingLog, bool takeOwnership)
{
m_MainLog = mainLog;
m_InterestingLog = interestingLog;
m_OwnsStreams = takeOwnership;
Init();
}
@ -89,8 +101,11 @@ CLogger::~CLogger ()
*m_InterestingLog << " at " << currentTime << buffer << "</p>\n";
*m_InterestingLog << html_footer;
delete m_InterestingLog;
delete m_MainLog;
if (m_OwnsStreams)
{
delete m_InterestingLog;
delete m_MainLog;
}
}
void CLogger::WriteMessage(const char *message, int interestedness)

View File

@ -27,19 +27,19 @@ public:
CLogger();
// Special constructor (mostly for testing) - outputs to provided streams.
// Takes ownership of streams and will delete them in the destructor.
CLogger(std::ostream* mainLog, std::ostream* interestingLog);
// Can take ownership of streams and delete them in the destructor.
CLogger(std::ostream* mainLog, std::ostream* interestingLog, bool takeOwnership);
~CLogger();
//Functions to write different message types
// Functions to write different message types
void WriteMessage(const char *message, int interestedness);
void WriteError (const char *message, int interestedness);
void WriteWarning(const char *message, int interestedness);
//Function to log stuff to file
// Function to log stuff to file
void Log(ELogMethod method, const char* category, const char *fmt, ...);
//Similar to Log, but only outputs each message once no matter how many times it's called
// Similar to Log, but only outputs each message once no matter how many times it's called
void LogOnce(ELogMethod method, const char* category, const char *fmt, ...);
private:
@ -47,11 +47,12 @@ private:
void LogUsingMethod(ELogMethod method, const char* category, const char* message);
//the output streams
// the output streams
std::ostream* m_MainLog;
std::ostream* m_InterestingLog;
bool m_OwnsStreams;
//vars to hold message counts
// vars to hold message counts
int m_NumberOfMessages;
int m_NumberOfErrors;
int m_NumberOfWarnings;

87
source/ps/DllLoader.cpp Normal file
View File

@ -0,0 +1,87 @@
#include "precompiled.h"
#include "DllLoader.h"
#include "lib/posix.h"
#include "lib/lib.h"
void* const HANDLE_UNAVAILABLE = (void*)-1;
// TODO Use path_util instead, get the actual path to the ps_dbg exe and append
// the library name.
// note: on Linux, lib is prepended to the SO file name and we need to add ./
// to make dlopen look in the current working directory
#if OS_UNIX
static const char* prefix = "./lib"
#else
static const char* prefix = "";
#endif
// since some of our SOs export a C++ interface, it is critical that
// compiler options are the same between app and SO; therefore,
// we need to go with the debug version in debug builds.
// note: on Windows, the extension is replaced with .dll by dlopen.
#ifndef NDEBUG
static const char* suffix = "_dbg.so";
#else
static const char* suffix = ".so";
#endif
// (This class is currently only used by 'Collada' and 'AtlasUI' which follow
// the naming/location convention above - it'll need to be changed if we want
// to support other DLLs.)
DllLoader::DllLoader(const char* name)
: m_Name(name), m_Handle(0)
{
}
DllLoader::~DllLoader()
{
if (IsLoaded())
dlclose(m_Handle);
}
bool DllLoader::IsLoaded() const
{
return (m_Handle != 0 && m_Handle != HANDLE_UNAVAILABLE);
}
bool DllLoader::LoadDLL()
{
// first time: try to open the shared object
// postcondition: m_Handle valid or == HANDLE_UNAVAILABLE.
if (m_Handle == 0)
{
CStr filename = CStr(prefix) + m_Name + suffix;
// we don't really care when relocations take place, but one of
// {RTLD_NOW, RTLD_LAZY} must be passed. go with the former because
// it is safer and matches the Windows load behavior.
const int flags = RTLD_LOCAL|RTLD_NOW;
m_Handle = dlopen(filename, flags);
// open failed (mostly likely SO not found)
if (! m_Handle)
m_Handle = HANDLE_UNAVAILABLE;
}
return (m_Handle != HANDLE_UNAVAILABLE);
}
void DllLoader::LoadSymbolInternal(const char* name, void** fptr) const
{
if (! IsLoaded())
{
debug_warn("Loading symbol from invalid DLL");
*fptr = NULL;
throw PSERROR_DllLoader_DllNotLoaded();
}
*fptr = dlsym(m_Handle, name);
if (*fptr == NULL)
throw PSERROR_DllLoader_SymbolNotFound();
}

63
source/ps/DllLoader.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef DLLLOADER_H__
#define DLLLOADER_H__
#include "ps/Errors.h"
ERROR_GROUP(DllLoader);
ERROR_TYPE(DllLoader, DllNotLoaded);
ERROR_TYPE(DllLoader, SymbolNotFound);
class DllLoader
{
public:
/**
* Prepare the DLL loader. Does no actual work.
*
* @param name base name of the library (from which we'll derive
* "name.dll", "libname_dbg.so", etc). Pointer must remain valid for
* this object's lifetime (which is fine if you just use a string literal).
*/
DllLoader(const char* name);
~DllLoader();
/**
* Attempt to load and initialise the library, if not already. Can be harmlessly
* called multiple times. Returns false if unsuccessful.
*/
bool LoadDLL();
/**
* Check whether the library has been loaded successfully. Returns false
* before {@link #LoadDLL} has been called; otherwise returns the same as
* LoadDLL did.
*/
bool IsLoaded() const;
/**
* Attempt to load a named symbol from the library. If {@link #IsLoaded} is
* false, throws PSERROR_DllLoader_DllNotLoaded. If it cannot load the
* symbol, throws PSERROR_DllLoader_SymbolNotFound. In both cases, sets fptr
* to NULL. Otherwise, fptr is set to point to the loaded function.
*
* @throws PSERROR_DllLoader
*/
template <typename T>
void LoadSymbol(const char* name, T& fptr) const;
private:
// Typeless version - the public LoadSymbol hides the slightly ugly
// casting from users.
void LoadSymbolInternal(const char* name, void** fptr) const;
const char* m_Name;
void* m_Handle;
};
template <typename T>
void DllLoader::LoadSymbol(const char* name, T& fptr) const
{
LoadSymbolInternal(name, (void**)&fptr);
}
#endif // DLLLOADER_H__

View File

@ -1,70 +1,15 @@
#include "precompiled.h"
#include "lib/posix.h"
#include "lib/lib.h"
#include "ps/GameSetup/CmdLineArgs.h"
#include "Atlas.h"
#include "ps/GameSetup/CmdLineArgs.h"
#include "ps/DllLoader.h"
//----------------------------------------------------------------------------
// Atlas (map editor) integration
//----------------------------------------------------------------------------
static void* const ATLAS_SO_UNAVAILABLE = (void*)-1;
static void* atlas_so_handle = NULL;
// Calculate the correct AtlasUI DLL
// TODO Use path_util instead, get the actual path to the ps_dbg exe and append
// the library name.
// note: on Linux, lib is prepended to the SO file name and we need to add ./
// to make dlopen look in the current working directory
#if OS_UNIX
# define PREFIX "./lib"
#else
# define PREFIX ""
#endif
// since this SO exports a C++ interface, it is critical that
// compiler options are the same between app and SO; therefore,
// we need to go with the debug version in debug builds.
// note: on Windows, the extension is replaced with .dll by dlopen.
#ifndef NDEBUG
static const char* so_name = PREFIX "AtlasUI_dbg.so";
#else
static const char* so_name = PREFIX "AtlasUI.so";
#endif
// free reference to Atlas UI SO (avoids resource leak report)
void ATLAS_Shutdown()
{
// (avoid dlclose warnings)
if(atlas_so_handle != 0 && atlas_so_handle != ATLAS_SO_UNAVAILABLE)
dlclose(atlas_so_handle);
}
// return true if the Atlas UI shared object is available;
// used to disable the main menu editor button if not.
// note: this actually loads the SO, but that isn't expected to be slow.
// call ATLAS_Shutdown at exit to avoid leaking it.
static bool ATLAS_IsAvailable()
{
// first time: try to open Atlas UI shared object
// postcondition: atlas_so_handle valid or == ATLAS_SO_UNAVAILABLE.
if(atlas_so_handle == 0)
{
// we don't really care when relocations take place, but one of
// {RTLD_NOW, RTLD_LAZY} must be passed. go with the former because
// it is safer and matches the Windows load behavior.
const int flags = RTLD_LOCAL|RTLD_NOW;
atlas_so_handle = dlopen(so_name, flags);
// open failed (mostly likely SO not found)
if(!atlas_so_handle)
atlas_so_handle = ATLAS_SO_UNAVAILABLE;
}
return atlas_so_handle != ATLAS_SO_UNAVAILABLE;
}
DllLoader atlas_dll("AtlasUI");
enum AtlasRunFlags
{
@ -78,7 +23,7 @@ enum AtlasRunFlags
static void ATLAS_Run(const CmdLineArgs& args, int flags = 0)
{
// first check if we can run at all
if(!ATLAS_IsAvailable())
if(!atlas_dll.LoadDLL())
{
if(flags & ATLAS_NO_GUI)
DISPLAY_ERROR(L"The Atlas UI was not successfully loaded and therefore cannot be started as requested.");
@ -88,8 +33,8 @@ static void ATLAS_Run(const CmdLineArgs& args, int flags = 0)
}
// TODO (make nicer)
extern bool BeginAtlas(const CmdLineArgs& args, void* dll);
if (!BeginAtlas(args, atlas_so_handle))
extern bool BeginAtlas(const CmdLineArgs& args, const DllLoader& dll);
if (!BeginAtlas(args, atlas_dll))
{
debug_warn("Atlas loading failed");
return;
@ -114,13 +59,3 @@ bool ATLAS_RunIfOnCmdLine(const CmdLineArgs& args)
return false;
}

View File

@ -135,9 +135,6 @@ static void ProcessCommandLineArgs(const CmdLineArgs& args)
if (args.Has("listfiles"))
trace_enable(true);
if (args.Has("novbo"))
g_ConfigDB.CreateValue(CFG_COMMAND, "novbo")->m_String = "true";
if (args.Has("profile"))
g_ConfigDB.CreateValue(CFG_COMMAND, "profile")->m_String = args.Get("profile");

View File

@ -4,29 +4,31 @@
#include "lib/res/file/vfs.h"
#include "lib/res/file/path.h"
#include "lib/res/file/trace.h"
#include "lib/res/h_mgr.h"
class TestXeromyces : public CxxTest::TestSuite
{
public:
void test_paths()
{
file_init();
path_init();
file_set_root_dir(0, "../data");
TS_ASSERT_OK(file_init());
TS_ASSERT_OK(file_set_root_dir(0, "../data"));
vfs_init();
vfs_mount("", "mods/_tests", VFS_MOUNT_RECURSIVE);
vfs_set_write_target("mods/_tests");
TS_ASSERT_OK(vfs_mount("", "mods/_test.xero", VFS_MOUNT_RECURSIVE));
TS_ASSERT_OK(vfs_set_write_target("mods/_test.xero"));
char xmbPath[PATH_MAX];
CXeromyces::GetXMBPath("test1.xml", "test1.xmb", xmbPath);
TS_ASSERT_STR_EQUALS(xmbPath, "cache/mods/_tests/xmb/test1.xmb");
TS_ASSERT_STR_EQUALS(xmbPath, "cache/mods/_test.xero/xmb/test1.xmb");
CXeromyces::GetXMBPath("a/b/test1.xml", "a/b/test1.xmb", xmbPath);
TS_ASSERT_STR_EQUALS(xmbPath, "cache/mods/_tests/xmb/a/b/test1.xmb");
TS_ASSERT_STR_EQUALS(xmbPath, "cache/mods/_test.xero/xmb/a/b/test1.xmb");
vfs_shutdown();
h_mgr_shutdown();
path_reset_root_dir();
TS_ASSERT_OK(file_shutdown());
}
};

View File

@ -63,7 +63,7 @@ public:
mainlog = new std::stringstream();
interestinglog = new std::stringstream();
logger = new CLogger(mainlog, interestinglog);
logger = new CLogger(mainlog, interestinglog, true);
lines.clear();
}

40
source/test_setup.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "precompiled.h"
#include <cxxtest/GlobalFixture.h>
class LeakReporter : public CxxTest::GlobalFixture
{
virtual bool tearDownWorld()
{
// Enable leak reporting on exit.
// (This is done in tearDownWorld so that it doesn't report 'leaks'
// if the program is aborted before finishing cleanly.)
#ifdef _MSC_VER
int flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
flags |= _CRTDBG_LEAK_CHECK_DF; // check for memory leaks
flags |= _CRTDBG_ALLOC_MEM_DF; // also check allocs using the non-debug version of new
_CrtSetDbgFlag(flags);
// Send output to stdout as well as the debug window, so it works during
// the normal build process as well as when debugging the test .exe
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE|_CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
#endif
return true;
}
virtual bool setUpWorld()
{
#ifdef _MSC_VER
// (Warning: the allocation numbers seem to differ by 3 when you
// run in the build process vs the debugger)
// _CrtSetBreakAlloc(1952);
#endif
return true;
}
};
static LeakReporter leakReporter;

View File

@ -488,9 +488,12 @@ private:
void complain(const SAXParseException& err, const wchar_t* severity) {
sawErrors = true;
C_ASSERT(sizeof(utf16_t) == sizeof(XMLCh));
errorText += wtoutf16(L"XML ")+wtoutf16(severity)
+wtoutf16(L": ")+ (utf16_t*)err.getSystemId()
+wtoutf16(L" / ") + (utf16_t*)err.getMessage();
errorText += wtoutf16(L"XML ");
errorText += wtoutf16(severity);
errorText += wtoutf16(L": ");
errorText += (utf16_t*)err.getSystemId();
errorText += wtoutf16(L" / ");
errorText += (utf16_t*)err.getMessage();
}
};

View File

@ -16,6 +16,7 @@
#include "lib/timer.h"
#include "lib/res/file/vfs.h"
#include "ps/CLogger.h"
#include "ps/DllLoader.h"
using namespace AtlasMessage;
@ -74,21 +75,25 @@ static ErrorReaction AtlasDisplayError(const wchar_t* text, uint flags)
return ER_CONTINUE;
}
bool BeginAtlas(const CmdLineArgs& args, void* dll)
bool BeginAtlas(const CmdLineArgs& args, const DllLoader& dll)
{
// Load required symbols from the DLL
#define GET(x) *(void**)&x = dlsym(dll, #x); debug_assert(x); if (! x) return false;
GET(Atlas_StartWindow);
GET(Atlas_SetMessagePasser);
GET(Atlas_GLSetCurrent);
GET(Atlas_GLSwapBuffers);
GET(Atlas_NotifyEndOfFrame);
GET(Atlas_DisplayError);
#undef GET
#define GET(x) *(void**)&x##Fptr = dlsym(dll, #x); debug_assert(x##Fptr); if (! x##Fptr) return false;
GET(ShareableMalloc);
GET(ShareableFree);
#undef GET
try
{
dll.LoadSymbol("Atlas_StartWindow", Atlas_StartWindow);
dll.LoadSymbol("Atlas_SetMessagePasser", Atlas_SetMessagePasser);
dll.LoadSymbol("Atlas_GLSetCurrent", Atlas_GLSetCurrent);
dll.LoadSymbol("Atlas_GLSwapBuffers", Atlas_GLSwapBuffers);
dll.LoadSymbol("Atlas_NotifyEndOfFrame", Atlas_NotifyEndOfFrame);
dll.LoadSymbol("Atlas_DisplayError", Atlas_DisplayError);
dll.LoadSymbol("ShareableMalloc", ShareableMallocFptr);
dll.LoadSymbol("ShareableFree", ShareableFreeFptr);
}
catch (PSERROR_DllLoader&)
{
debug_warn("Failed to initialise DLL");
return false;
}
// Pass our message handler to Atlas
Atlas_SetMessagePasser(&msgPasser);