GNU C++ project makefile generation (placeholder); refactoring and code cleanup (r346:349)

This commit is contained in:
starkos 2008-05-02 13:51:44 +00:00
parent a2fc0b2854
commit 35301621dc
18 changed files with 491 additions and 235 deletions

View File

@ -41,6 +41,8 @@ OBJECTS := \
RESOURCES := \
# Can I have premake check the OS type instead of doing this here?
MKDIR_TYPE := msdos
CMD := $(subst \,\\,$(ComSpec)$(COMSPEC))
ifeq (,$(CMD))
@ -63,6 +65,8 @@ endif
.PHONY: clean
# I really only need to create OUTDIR; that's the only one that matters!
$(OUTDIR)/$(TARGET): $(OBJECTS) $(LDDEPS) $(RESOURCES)
@echo Linking CppExe
-@$(CMD_MKBINDIR)
@ -81,6 +85,9 @@ else
-@if exist $(subst /,\,$(OBJDIR)) rmdir /s /q $(subst /,\,$(OBJDIR))
endif
# add an "objdir" as first dependency to target and create directories there (or maybe
# call it outdirs and do all required output directories
$(OBJDIR)/Hello.o: Hello.cpp
-@$(CMD_MKOBJDIR)
@echo $(notdir $<)

View File

@ -9,6 +9,7 @@
#include "action/action.h"
#include "make.h"
#include "make_solution.h"
#include "make_project.h"
/** The GNU make solution writing process, for session_enumerate_objects() */
@ -27,6 +28,14 @@ static SessionSolutionCallback SolutionCallbacks[] =
/** The GNU make project writing process, for session_enumerate_objects() */
static SessionProjectCallback ProjectCallbacks[] =
{
make_project_create,
make_project_signature,
session_enumerate_configurations,
make_project_objects,
make_project_resources,
make_project_phony_rule,
make_project_target,
make_project_include_dependencies,
NULL
};
@ -34,6 +43,17 @@ static SessionProjectCallback ProjectCallbacks[] =
/** The GNU make configuration writing process, for session_enumerate_configurations() */
static SessionProjectCallback ConfigCallbacks[] =
{
make_project_config_conditional,
make_project_config_outdir,
make_project_config_outfile,
make_project_config_objdir,
make_project_config_cppflags,
make_project_config_cflags,
make_project_config_cxxflags,
make_project_config_ldflags,
make_project_config_lddeps,
make_project_config_resflags,
make_project_config_end,
NULL
};

View File

@ -0,0 +1,236 @@
/**
* \file make_project.c
* \brief Makefile project generation functions.
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
*/
#include <assert.h>
#include "premake.h"
#include "action/make/make.h"
#include "action/make/make_project.h"
#include "base/error.h"
/**
* Write the opening conditional for a configuration block.
*/
int make_project_config_conditional(Session sess, Project prj, Stream strm)
{
const char* cfg_name = project_get_configuration_filter(prj);
UNUSED(sess);
return stream_writeline(strm, "ifeq ($(CONFIG),%s)", cfg_name);
}
/**
* Write the CFLAGS configuration variable.
*/
int make_project_config_cflags(Session sess, Project prj, Stream strm)
{
UNUSED(sess);
UNUSED(prj);
return stream_writeline(strm, " CFLAGS += $(CPPFLAGS) $(ARCHFLAGS)");
}
/**
* Write the CPPFLAGS configuration variable.
*/
int make_project_config_cppflags(Session sess, Project prj, Stream strm)
{
UNUSED(sess);
UNUSED(prj);
return stream_writeline(strm, " CPPFLAGS += -MMD");
}
/**
* Write the CXXFLAGS configuration variable.
*/
int make_project_config_cxxflags(Session sess, Project prj, Stream strm)
{
UNUSED(sess);
UNUSED(prj);
return stream_writeline(strm, " CXXFLAGS += $(CFLAGS)");
}
/**
* Write the opening conditional for a configuration block.
*/
int make_project_config_end(Session sess, Project prj, Stream strm)
{
int z;
UNUSED(sess);
UNUSED(prj);
z = stream_writeline(strm, "endif");
z |= stream_writeline(strm, "");
return z;
}
/**
* Write the LDDEPS configuration variable.
*/
int make_project_config_lddeps(Session sess, Project prj, Stream strm)
{
UNUSED(sess);
UNUSED(prj);
return stream_writeline(strm, " LDDEPS :=");
}
/**
* Write the LDFLAGS configuration variable.
*/
int make_project_config_ldflags(Session sess, Project prj, Stream strm)
{
UNUSED(sess);
UNUSED(prj);
return stream_writeline(strm, " LDFLAGS +=");
}
/**
* Write the OBJDIR configuration variable.
*/
int make_project_config_objdir(Session sess, Project prj, Stream strm)
{
const char* cfg_name = project_get_configuration_filter(prj);
UNUSED(sess);
return stream_writeline(strm, " OBJDIR := obj/%s", cfg_name);
}
/**
* Write the OUTDIR configuration variable.
*/
int make_project_config_outdir(Session sess, Project prj, Stream strm)
{
UNUSED(sess);
UNUSED(prj);
return stream_writeline(strm, " OUTDIR := .");
}
/**
* Write the OUTFILE configuration variable.
*/
int make_project_config_outfile(Session sess, Project prj, Stream strm)
{
UNUSED(sess);
UNUSED(prj);
return stream_writeline(strm, " OUTFILE := MyApp");
}
/**
* Write the RESFLAGS configuration variable.
*/
int make_project_config_resflags(Session sess, Project prj, Stream strm)
{
UNUSED(sess);
UNUSED(prj);
return stream_writeline(strm, " RESFLAGS +=");
}
/**
* Create a new output stream for a project , and make it active for subsequent writes.
*/
int make_project_create(Session sess, Project prj, Stream strm)
{
/* create the makefile */
const char* filename = make_get_project_makefile(sess, prj);
strm = stream_create_file(filename);
if (!strm)
{
return !OKAY;
}
/* make the stream active for the functions that come after */
session_set_active_stream(sess, strm);
return OKAY;
}
/**
* Include the auto-generated dependencies into the project makefile.
*/
int make_project_include_dependencies(Session sess, Project prj, Stream strm)
{
UNUSED(sess);
UNUSED(prj);
return stream_writeline(strm, "-include $(OBJECTS:%%.o=%%.d)");
}
/**
* Write the OBJECTS project variable.
*/
int make_project_objects(Session sess, Project prj, Stream strm)
{
int z;
UNUSED(sess);
UNUSED(prj);
z = stream_writeline(strm, "OBJECTS := \\");
z |= stream_writeline(strm, "");
return z;
}
/**
* Write the .PHONY rule for a project.
*/
int make_project_phony_rule(Session sess, Project prj, Stream strm)
{
int z;
UNUSED(sess);
UNUSED(prj);
z = stream_writeline(strm, ".PHONY: clean");
z |= stream_writeline(strm, "");
return z;
}
/**
* Write the RESOURCES project variable.
*/
int make_project_resources(Session sess, Project prj, Stream strm)
{
int z;
UNUSED(sess);
UNUSED(prj);
z = stream_writeline(strm, "RESOURCES := \\");
z |= stream_writeline(strm, "");
return z;
}
/**
* Write the project makefile signature.
*/
int make_project_signature(Session sess, Project prj, Stream strm)
{
int z;
UNUSED(sess);
UNUSED(prj);
z = stream_writeline(strm, "# GNU Makefile autogenerated by Premake");
z |= stream_writeline(strm, "");
return z;
}
/**
* Write the project output target rule.
*/
int make_project_target(Session sess, Project prj, Stream strm)
{
int z;
UNUSED(sess);
z = stream_writeline(strm, "$(OUTDIR)/$(OUTFILE): $(OBJECTS) $(LDDEPS) $(RESOURCES)");
z |= stream_writeline(strm, "\t@echo Linking %s", project_get_name(prj));
z |= stream_writeline(strm, "\t$(CXX) -o $@ $(LDFLAGS) $(ARCHFLAGS) $(OBJECTS) $(RESOURCES)");
z |= stream_writeline(strm, "");
return z;
}

View File

@ -0,0 +1,30 @@
/**
* \file make_project.h
* \brief Makefile project generation functions.
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
*/
#if !defined(PREMAKE_MAKE_PROJECT_H)
#define PREMAKE_MAKE_PROJECT_H
#include "engine/session.h"
int make_project_config_conditional(Session sess, Project prj, Stream strm);
int make_project_config_cflags(Session sess, Project prj, Stream strm);
int make_project_config_cppflags(Session sess, Project prj, Stream strm);
int make_project_config_cxxflags(Session sess, Project prj, Stream strm);
int make_project_config_end(Session sess, Project prj, Stream strm);
int make_project_config_lddeps(Session sess, Project prj, Stream strm);
int make_project_config_ldflags(Session sess, Project prj, Stream strm);
int make_project_config_objdir(Session sess, Project prj, Stream strm);
int make_project_config_outdir(Session sess, Project prj, Stream strm);
int make_project_config_outfile(Session sess, Project prj, Stream strm);
int make_project_config_resflags(Session sess, Project prj, Stream strm);
int make_project_create(Session sess, Project prj, Stream strm);
int make_project_include_dependencies(Session sess, Project prj, Stream strm);
int make_project_objects(Session sess, Project prj, Stream strm);
int make_project_phony_rule(Session sess, Project prj, Stream strm);
int make_project_resources(Session sess, Project prj, Stream strm);
int make_project_signature(Session sess, Project prj, Stream strm);
int make_project_target(Session sess, Project prj, Stream strm);
#endif

View File

@ -0,0 +1,158 @@
/**
* \file gmake_project_tests.cpp
* \brief Automated tests for GNU makefile project processing.
* \author Copyright (c) 2008 Jason Perkins and the Premake project
*/
#include "premake.h"
#include "action/tests/action_tests.h"
extern "C" {
#include "action/make/make_project.h"
}
SUITE(action)
{
TEST_FIXTURE(FxAction, MakeProject_Signature)
{
make_project_signature(sess, prj, strm);
CHECK_EQUAL(
"# GNU Makefile autogenerated by Premake\n"
"\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Config_Conditional)
{
make_project_config_conditional(sess, prj, strm);
CHECK_EQUAL(
"ifeq ($(CONFIG),Debug)\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Config_End)
{
make_project_config_end(sess, prj, strm);
CHECK_EQUAL(
"endif\n"
"\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Config_CFlags)
{
make_project_config_cflags(sess, prj, strm);
CHECK_EQUAL(
" CFLAGS += $(CPPFLAGS) $(ARCHFLAGS)\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Config_CppFlags)
{
make_project_config_cppflags(sess, prj, strm);
CHECK_EQUAL(
" CPPFLAGS += -MMD\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Config_CxxFlags)
{
make_project_config_cxxflags(sess, prj, strm);
CHECK_EQUAL(
" CXXFLAGS += $(CFLAGS)\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Config_LdDeps)
{
make_project_config_lddeps(sess, prj, strm);
CHECK_EQUAL(
" LDDEPS :=\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Config_LdFlags)
{
make_project_config_ldflags(sess, prj, strm);
CHECK_EQUAL(
" LDFLAGS +=\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Config_ObjDir)
{
make_project_config_objdir(sess, prj, strm);
CHECK_EQUAL(
" OBJDIR := obj/Debug\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Config_OutFile)
{
make_project_config_outfile(sess, prj, strm);
CHECK_EQUAL(
" OUTFILE := MyApp\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Config_OutDir)
{
make_project_config_outdir(sess, prj, strm);
CHECK_EQUAL(
" OUTDIR := .\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Config_ResFlags)
{
make_project_config_resflags(sess, prj, strm);
CHECK_EQUAL(
" RESFLAGS +=\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Objects)
{
make_project_objects(sess, prj, strm);
CHECK_EQUAL(
"OBJECTS := \\\n"
"\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_Resources)
{
make_project_resources(sess, prj, strm);
CHECK_EQUAL(
"RESOURCES := \\\n"
"\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_PhonyRule)
{
make_project_phony_rule(sess, prj, strm);
CHECK_EQUAL(
".PHONY: clean\n"
"\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_OutputTarget)
{
make_project_target(sess, prj, strm);
CHECK_EQUAL(
"$(OUTDIR)/$(OUTFILE): $(OBJECTS) $(LDDEPS) $(RESOURCES)\n"
"\t@echo Linking MyProject\n"
"\t$(CXX) -o $@ $(LDFLAGS) $(ARCHFLAGS) $(OBJECTS) $(RESOURCES)\n"
"\n",
buffer);
}
TEST_FIXTURE(FxAction, MakeProject_IncludeDependencies)
{
make_project_include_dependencies(sess, prj, strm);
CHECK_EQUAL(
"-include $(OBJECTS:%.o=%.d)\n",
buffer);
}
}

View File

@ -40,6 +40,7 @@ struct FxAction
project_set_location(prj, "ProjectFolder");
project_set_guid(prj, "AE2461B7-236F-4278-81D3-F0D476F9A4C0");
project_set_language(prj, "c++");
project_set_configuration_filter(prj, "Debug");
}
~FxAction()

View File

@ -16,7 +16,6 @@ struct FxVsProject : FxAction
FxVsProject()
{
session_set_action(sess, "vs2002");
project_set_configuration_filter(prj, "Debug");
}
};

View File

@ -15,7 +15,7 @@
/** The VS2002 solution writing process, for session_enumerate_objects() */
static SessionSolutionCallback SolutionCallbacks[] =
{
vs2002_solution_create,
vs200x_solution_create,
vs2002_solution_signature,
vs2002_solution_projects,
vs2002_solution_configuration,

View File

@ -40,29 +40,6 @@ int vs2002_solution_configuration(Session sess, Solution sln, Stream strm)
}
/**
* Create a new output stream for a solution, and make it active for subsequent writes.
* \param sess The execution session context.
* \param sln The current solution.
* \param strm The currently active stream; set with session_set_active_stream().
* \returns OKAY if successful.
*/
int vs2002_solution_create(Session sess, Solution sln, Stream strm)
{
/* create the solution file */
const char* filename = solution_get_filename(sln, NULL, ".sln");
strm = stream_create_file(filename);
if (!strm)
{
return !OKAY;
}
/* make the stream active for the functions that come after */
session_set_active_stream(sess, strm);
return OKAY;
}
/**
* Create the Visual Studio 2002 project dependencies block.
* \param sess The execution session context.

View File

@ -15,7 +15,7 @@
/** The VS2003 solution writing process, for session_enumerate_objects() */
static SessionSolutionCallback SolutionCallbacks[] =
{
vs2002_solution_create,
vs200x_solution_create,
vs2003_solution_signature,
vs2002_solution_projects,
vs2003_solution_configuration,

View File

@ -15,7 +15,7 @@
/** The VS2005 solution writing process, for session_enumerate_objects() */
static SessionSolutionCallback SolutionCallbacks[] =
{
vs2002_solution_create,
vs200x_solution_create,
vs2005_solution_signature,
vs2002_solution_projects,
vs2005_solution_platforms,

View File

@ -15,7 +15,7 @@
/** The VS2008 solution writing process, for session_enumerate_objects() */
static SessionSolutionCallback SolutionCallbacks[] =
{
vs2002_solution_create,
vs200x_solution_create,
vs2008_solution_signature,
vs2002_solution_projects,
vs2005_solution_platforms,

View File

@ -18,10 +18,7 @@ int vs200x_project_config_element(Session sess, Project prj, Stream strm)
{
int z;
const char* cfg_name = project_get_configuration_filter(prj);
UNUSED(prj);
UNUSED(strm);
z = vs200x_element_start(sess, 2, "Configuration");
z |= vs200x_attribute(sess, 2, "Name", "%s|Win32", cfg_name);
z |= vs200x_attribute(sess, 2, "OutputDirectory", "$(SolutionDir)$(ConfigurationName)");

View File

@ -0,0 +1,33 @@
/**
* \file vs200x_solution.c
* \brief Visual Studio multiple-version solution generation functions.
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
*/
#include <stdlib.h>
#include "premake.h"
#include "vs200x.h"
#include "vs200x_solution.h"
/**
* Create a new output stream for a solution, and make it active for subsequent writes.
* \param sess The execution session context.
* \param sln The current solution.
* \param strm The currently active stream; set with session_set_active_stream().
* \returns OKAY if successful.
*/
int vs200x_solution_create(Session sess, Solution sln, Stream strm)
{
/* create the solution file */
const char* filename = solution_get_filename(sln, NULL, ".sln");
strm = stream_create_file(filename);
if (!strm)
{
return !OKAY;
}
/* make the stream active for the functions that come after */
session_set_active_stream(sess, strm);
return OKAY;
}

View File

@ -9,7 +9,6 @@
#include "engine/session.h"
int vs2002_solution_configuration(Session sess, Solution sln, Stream strm);
int vs2002_solution_create(Session sess, Solution sln, Stream strm);
int vs2002_solution_dependencies(Session sess, Solution sln, Stream strm);
int vs2002_solution_extensibility(Session sess, Solution sln, Stream strm);
int vs2002_solution_project_configuration(Session sess, Solution sln, Stream strm);
@ -26,4 +25,6 @@ int vs2005_solution_signature(Session sess, Solution sln, Stream strm);
int vs2008_solution_signature(Session sess, Solution sln, Stream strm);
int vs200x_solution_create(Session sess, Solution sln, Stream strm);
#endif

View File

@ -1,64 +0,0 @@
/**
* \file xml_tests.cpp
* \brief XML output tests.
* \author Copyright (c) 2007-2008 Jason Perkins and the Premake project
*/
#include "premake.h"
#include "testing/testing.h"
extern "C" {
#include "base/stream.h"
#include "base/xml.h"
}
struct FxXml
{
Stream strm;
Xml xml;
char buffer[1024];
FxXml()
{
strm = stream_create_null();
stream_set_buffer(strm, buffer);
xml = xml_create(strm);
}
~FxXml()
{
xml_destroy(xml);
stream_destroy(strm);
}
};
SUITE(base)
{
TEST_FIXTURE(FxXml, EndElement_Short)
{
xml_element_start(xml, "MyElement");
xml_element_end(xml, "MyElement");
CHECK_EQUAL("<MyElement/>\n", buffer);
}
TEST_FIXTURE(FxXml, EndElement_Full)
{
xml_element_start(xml, "MyElement");
xml_element_end_full(xml, "MyElement");
CHECK_EQUAL("<MyElement>\n</MyElement>\n", buffer);
}
TEST_FIXTURE(FxXml, ElementNesting_OneDeep)
{
xml_element_start(xml, "Element0");
xml_element_start(xml, "Element1");
xml_element_end(xml, "Element1");
xml_element_end(xml, "Element0");
CHECK_EQUAL(
"<Element0>\n"
"\t<Element1/>\n"
"</Element0>\n",
buffer);
}
}

View File

@ -1,120 +0,0 @@
/**
* \file xml.c
* \brief XML output handling.
* \author Copyright (c) 2007-2008 Jason Perkins and the Premake project
*/
#include <assert.h>
#include <stdlib.h>
#include "premake.h"
#include "xml.h"
DEFINE_CLASS(Xml)
{
Stream strm;
int element_depth;
int has_children;
};
/**
* Create a new XML output object around a stream.
* \param strm The stream to which to write XML output.
* \returns A new XML output object.
*/
Xml xml_create(Stream strm)
{
Xml xml;
assert(strm);
xml = ALLOC_CLASS(Xml);
xml->strm = strm;
xml->element_depth = 0;
xml->has_children = 0;
return xml;
}
/**
* Destroy an XML output object and release the associated memory. The stream associated
* with the object is left intact, and not closed or destroyed.
* \param xml The XML output object to destroy.
*/
void xml_destroy(Xml xml)
{
assert(xml);
free(xml);
}
/**
* Close the current element tag.
* \param xml The XML output object.
* \param element_name The name of the element being ended.
* \returns OKAY if successful.
*/
int xml_element_end(Xml xml, const char* element_name)
{
int z = OKAY;
assert(xml);
assert(element_name);
if (xml->has_children)
{
z |= stream_writeline(xml->strm, "</%s>", element_name);
}
else
{
z |= stream_writeline(xml->strm, "/>");
}
xml->element_depth--;
xml->has_children = 1;
return z;
}
/**
* Close the current element tag, using the full (</ElementName>) form.
* \param xml The XML output object.
* \param element_name The name of the element being ended.
* \returns OKAY if successful.
*/
int xml_element_end_full(Xml xml, const char* element_name)
{
int z;
assert(xml);
z = stream_writeline(xml->strm, ">");
z |= stream_writeline(xml->strm, "</%s>", element_name);
return z;
}
/**
* Start writing a new element tag.
* \param xml The XML output object.
* \param element_name The name of the new element.
* \returns OKAY if successful.
*/
int xml_element_start(Xml xml, const char* element_name)
{
int i, z = OKAY;
assert(xml);
assert(element_name);
if (xml->element_depth > 0)
{
z |= stream_writeline(xml->strm, ">");
}
for (i = 0; i < xml->element_depth; ++i)
{
z |= stream_write(xml->strm, "\t");
}
xml->element_depth++;
z |= stream_write(xml->strm, "<%s", element_name);
return z;
}

View File

@ -1,19 +0,0 @@
/**
* \file xml.h
* \brief XML output handling.
* \author Copyright (c) 2007-2008 Jason Perkins and the Premake project
*/
#if !defined(PREMAKE_XML_H)
#define PREMAKE_XML_H
#include "base/stream.h"
DECLARE_CLASS(Xml);
Xml xml_create(Stream strm);
void xml_destroy(Xml xml);
int xml_element_end(Xml xml, const char* element_name);
int xml_element_end_full(Xml xml, const char* element_name);
int xml_element_start(Xml xml, const char* element_name);
#endif