From 8377b2e217b197c2faf2a387742d4af43171d186 Mon Sep 17 00:00:00 2001 From: starkos Date: Sun, 18 May 2008 15:20:32 +0000 Subject: [PATCH] Added mkdir and clean rules to gmake (r380:382) --- src/action/make/gmake.c | 3 + src/action/make/gmake_project.c | 49 ++++++++++++++++ src/action/make/make_project.c | 58 ++++++++++++++++--- src/action/make/make_project.h | 4 ++ src/action/make/tests/gmake_project_tests.cpp | 57 +++++++++++++++--- src/base/cstr.c | 30 +++++++++- src/base/cstr.h | 1 + src/base/path.c | 3 +- src/base/tests/cstr_tests.cpp | 25 ++++++++ 9 files changed, 210 insertions(+), 20 deletions(-) create mode 100644 src/action/make/gmake_project.c diff --git a/src/action/make/gmake.c b/src/action/make/gmake.c index 7f64f698..76b433f6 100644 --- a/src/action/make/gmake.c +++ b/src/action/make/gmake.c @@ -33,8 +33,11 @@ static SessionProjectCallback ProjectCallbacks[] = session_enumerate_configurations, make_project_objects, make_project_resources, + gmake_project_shell_detect, make_project_phony_rule, make_project_target, + make_project_mkdir_rules, + make_project_clean_rules, make_project_source_rules, make_project_include_dependencies, NULL diff --git a/src/action/make/gmake_project.c b/src/action/make/gmake_project.c new file mode 100644 index 00000000..f147b227 --- /dev/null +++ b/src/action/make/gmake_project.c @@ -0,0 +1,49 @@ +/** + * \file gmake_project.c + * \brief GNU makefile project generation functions. + * \author Copyright (c) 2002-2008 Jason Perkins and the Premake project + */ + +#include "premake.h" +#include "make_project.h" + + +/** + * Write the shell detection block, which is used while building on Windows in + * order to detect the enclosing shell type: MS-DOS, Cygwin, or MinGW. The shell + * determines how directories and files should be created and removed. + * + * While the detection in important only on Windows, I write for all platforms. + * This simplifies the code generation, and makes portable makefiles possible + * (even though most will have platform-specific bits in them). + */ +int gmake_project_shell_detect(Session sess, Project prj, Stream strm) +{ + int z = OKAY; + + UNUSED(sess); + UNUSED(prj); + + z |= stream_writeline(strm, "SHELLTYPE := msdos"); + z |= stream_writeline(strm, "ifeq (,$(ComSpec)$(COMSPEC))"); + z |= stream_writeline(strm, " SHELLTYPE := posix"); + z |= stream_writeline(strm, "endif"); + z |= stream_writeline(strm, "ifeq (/bin/sh.exe,$(SHELL))"); + z |= stream_writeline(strm, " SHELLTYPE := posix"); + z |= stream_writeline(strm, "endif"); + z |= stream_writeline(strm, ""); + z |= stream_writeline(strm, "ifeq (posix,$(SHELLTYPE))"); + z |= stream_writeline(strm, " MKDIR := mkdir -p"); + z |= stream_writeline(strm, " PATHSEP := /"); + z |= stream_writeline(strm, "else"); + z |= stream_writeline(strm, " MKDIR := mkdir"); + z |= stream_writeline(strm, " PATHSEP := \\\\"); + z |= stream_writeline(strm, "endif"); + z |= stream_writeline(strm, ""); + z |= stream_writeline(strm, "SYS_OUTDIR := $(subst /,$(PATHSEP),$(OUTDIR))"); + z |= stream_writeline(strm, "SYS_OUTFILE := $(subst /,$(PATHSEP),$(OUTFILE))"); + z |= stream_writeline(strm, "SYS_OBJDIR := $(subst /,$(PATHSEP),$(OBJDIR))"); + z |= stream_writeline(strm, ""); + return z; +} + diff --git a/src/action/make/make_project.c b/src/action/make/make_project.c index be4ce31c..01d23905 100644 --- a/src/action/make/make_project.c +++ b/src/action/make/make_project.c @@ -12,6 +12,27 @@ #include "base/path.h" +/** + * Write the rules to clean up output files on a `make clean`. + */ +int make_project_clean_rules(Session sess, Project prj, Stream strm) +{ + int z = OKAY; + UNUSED(sess); + z |= stream_writeline(strm, "clean:"); + z |= stream_writeline(strm, "\t@echo Cleaning %s", project_get_name(prj)); + z |= stream_writeline(strm, "ifeq (posix, $(SHELLTYPE))"); + z |= stream_writeline(strm, "\t@rm -f $(SYS_OUTFILE)"); + z |= stream_writeline(strm, "\t@rm -rf $(SYS_OBJDIR)"); + z |= stream_writeline(strm, "else"); + z |= stream_writeline(strm, "\t@if exist $(SYS_OUTFILE) del $(SYS_OUTFILE)"); + z |= stream_writeline(strm, "\t@if exist $(SYS_OBJDIR) rmdir /s /q $(SYS_OBJDIR)"); + z |= stream_writeline(strm, "endif"); + z |= stream_writeline(strm, ""); + return OKAY; +} + + /** * Write the opening conditional for a configuration block. */ @@ -30,7 +51,7 @@ int make_project_config_cflags(Session sess, Project prj, Stream strm) { UNUSED(sess); UNUSED(prj); - return stream_writeline(strm, " CFLAGS += $(CPPFLAGS) $(ARCHFLAGS)"); + return stream_writeline(strm, " CFLAGS += $(CPPFLAGS) $(ARCHFLAGS)"); } @@ -77,7 +98,7 @@ int make_project_config_lddeps(Session sess, Project prj, Stream strm) { UNUSED(sess); UNUSED(prj); - return stream_writeline(strm, " LDDEPS :="); + return stream_writeline(strm, " LDDEPS :="); } @@ -88,7 +109,7 @@ int make_project_config_ldflags(Session sess, Project prj, Stream strm) { UNUSED(sess); UNUSED(prj); - return stream_writeline(strm, " LDFLAGS +="); + return stream_writeline(strm, " LDFLAGS +="); } @@ -99,7 +120,7 @@ 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 := .", cfg_name); + return stream_writeline(strm, " OBJDIR := obj/%s", cfg_name); } @@ -110,7 +131,7 @@ int make_project_config_outdir(Session sess, Project prj, Stream strm) { UNUSED(sess); UNUSED(prj); - return stream_writeline(strm, " OUTDIR := ."); + return stream_writeline(strm, " OUTDIR := ."); } @@ -121,7 +142,7 @@ int make_project_config_outfile(Session sess, Project prj, Stream strm) { UNUSED(sess); UNUSED(prj); - return stream_writeline(strm, " OUTFILE := MyApp"); + return stream_writeline(strm, " OUTFILE := $(OUTDIR)/MyApp"); } @@ -166,6 +187,26 @@ int make_project_include_dependencies(Session sess, Project prj, Stream strm) } +/** + * Write the rules to create the output and object directories. + */ +int make_project_mkdir_rules(Session sess, Project prj, Stream strm) +{ + int z = OKAY; + UNUSED(sess); + UNUSED(prj); + z |= stream_writeline(strm, "$(OUTDIR):"); + z |= stream_writeline(strm, "\t@echo Creating $(OUTDIR)"); + z |= stream_writeline(strm, "\t@$(MKDIR) $(SYS_OUTDIR)"); + z |= stream_writeline(strm, ""); + z |= stream_writeline(strm, "$(OBJDIR):"); + z |= stream_writeline(strm, "\t@echo Creating $(OBJDIR)"); + z |= stream_writeline(strm, "\t@$(MKDIR) $(SYS_OBJDIR)"); + z |= stream_writeline(strm, ""); + return z; +} + + /** * Write the OBJECTS project variable. */ @@ -249,7 +290,6 @@ int make_project_source_rules(Session sess, Project prj, Stream strm) const char* filename = strings_item(files, i); const char* obj_name = make_get_obj_filename(filename); z |= stream_writeline(strm, "%s: %s", obj_name, filename); - z |= stream_writeline(strm, "\t-@$(CMD_MKOBJDIR)"); z |= stream_writeline(strm, "\t@echo $(notdir $<)"); z |= stream_writeline(strm, "\t@$(CXX) $(CXXFLAGS) -o $@ -c $<"); z |= stream_writeline(strm, ""); @@ -264,9 +304,9 @@ int make_project_source_rules(Session sess, Project prj, Stream strm) */ int make_project_target(Session sess, Project prj, Stream strm) { - int z; + int z = OKAY; UNUSED(sess); - z = stream_writeline(strm, "$(OUTDIR)/$(OUTFILE): $(OBJECTS) $(LDDEPS) $(RESOURCES)"); + z |= stream_writeline(strm, "$(OUTFILE): $(OUTDIR) $(OBJDIR) $(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, ""); diff --git a/src/action/make/make_project.h b/src/action/make/make_project.h index 05896bae..65482c19 100644 --- a/src/action/make/make_project.h +++ b/src/action/make/make_project.h @@ -8,6 +8,9 @@ #include "session/session.h" +int gmake_project_shell_detect(Session sess, Project prj, Stream strm); + +int make_project_clean_rules(Session sess, Project prj, Stream strm); 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); @@ -21,6 +24,7 @@ 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_mkdir_rules(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); diff --git a/src/action/make/tests/gmake_project_tests.cpp b/src/action/make/tests/gmake_project_tests.cpp index cbe242f5..1cb85951 100644 --- a/src/action/make/tests/gmake_project_tests.cpp +++ b/src/action/make/tests/gmake_project_tests.cpp @@ -42,7 +42,7 @@ SUITE(action) { make_project_config_cflags(sess, prj, strm); CHECK_EQUAL( - " CFLAGS += $(CPPFLAGS) $(ARCHFLAGS)\n", + " CFLAGS += $(CPPFLAGS) $(ARCHFLAGS)\n", buffer); } @@ -66,7 +66,7 @@ SUITE(action) { make_project_config_lddeps(sess, prj, strm); CHECK_EQUAL( - " LDDEPS :=\n", + " LDDEPS :=\n", buffer); } @@ -74,7 +74,7 @@ SUITE(action) { make_project_config_ldflags(sess, prj, strm); CHECK_EQUAL( - " LDFLAGS +=\n", + " LDFLAGS +=\n", buffer); } @@ -82,7 +82,7 @@ SUITE(action) { make_project_config_objdir(sess, prj, strm); CHECK_EQUAL( - " OBJDIR := .\n", + " OBJDIR := obj/Debug\n", buffer); } @@ -90,7 +90,7 @@ SUITE(action) { make_project_config_outfile(sess, prj, strm); CHECK_EQUAL( - " OUTFILE := MyApp\n", + " OUTFILE := $(OUTDIR)/MyApp\n", buffer); } @@ -98,7 +98,7 @@ SUITE(action) { make_project_config_outdir(sess, prj, strm); CHECK_EQUAL( - " OUTDIR := .\n", + " OUTDIR := .\n", buffer); } @@ -165,7 +165,7 @@ SUITE(action) { make_project_target(sess, prj, strm); CHECK_EQUAL( - "$(OUTDIR)/$(OUTFILE): $(OBJECTS) $(LDDEPS) $(RESOURCES)\n" + "$(OUTFILE): $(OUTDIR) $(OBJDIR) $(OBJECTS) $(LDDEPS) $(RESOURCES)\n" "\t@echo Linking MyProject\n" "\t$(CXX) -o $@ $(LDFLAGS) $(ARCHFLAGS) $(OBJECTS) $(RESOURCES)\n" "\n", @@ -173,6 +173,48 @@ SUITE(action) } + /********************************************************************** + * Directory creation rules + **********************************************************************/ + + TEST_FIXTURE(FxAction, MakeProject_MkdirRules) + { + make_project_mkdir_rules(sess, prj, strm); + CHECK_EQUAL( + "$(OUTDIR):\n" + "\t@echo Creating $(OUTDIR)\n" + "\t@$(MKDIR) $(SYS_OUTDIR)\n" + "\n" + "$(OBJDIR):\n" + "\t@echo Creating $(OBJDIR)\n" + "\t@$(MKDIR) $(SYS_OBJDIR)\n" + "\n", + buffer); + } + + + /********************************************************************** + * Clean rules + **********************************************************************/ + + TEST_FIXTURE(FxAction, MakeProject_CleanRules) + { + make_project_clean_rules(sess, prj, strm); + CHECK_EQUAL( + "clean:\n" + "\t@echo Cleaning MyProject\n" + "ifeq (posix, $(SHELLTYPE))\n" + "\t@rm -f $(SYS_OUTFILE)\n" + "\t@rm -rf $(SYS_OBJDIR)\n" + "else\n" + "\t@if exist $(SYS_OUTFILE) del $(SYS_OUTFILE)\n" + "\t@if exist $(SYS_OBJDIR) rmdir /s /q $(SYS_OBJDIR)\n" + "endif\n" + "\n", + buffer); + } + + /********************************************************************** * Source rule tests **********************************************************************/ @@ -184,7 +226,6 @@ SUITE(action) make_project_source_rules(sess, prj, strm); CHECK_EQUAL( "$(OBJDIR)/Hello.o: Hello.cpp\n" - "\t-@$(CMD_MKOBJDIR)\n" "\t@echo $(notdir $<)\n" "\t@$(CXX) $(CXXFLAGS) -o $@ -c $<\n" "\n", diff --git a/src/base/cstr.c b/src/base/cstr.c index 8e82d3c1..898a5692 100644 --- a/src/base/cstr.c +++ b/src/base/cstr.c @@ -4,6 +4,7 @@ * \author Copyright (c) 2002-2008 Jason Perkins and the Premake project */ +#include #include #include #include @@ -38,7 +39,7 @@ int cstr_ends_with(const char* str, const char* expected) * Compares two C strings for equality. * \param str The string to compare. * \param expected The value to compare against. - * \returns Nonzero if the strings match, zero otherwise. + * \returns True if the strings match, zero otherwise. */ int cstr_eq(const char* str, const char* expected) { @@ -50,6 +51,33 @@ int cstr_eq(const char* str, const char* expected) } +/** + * Performs a case-insensitive comparasion on two C strings for equality. + * \param str The string to compare. + * \param expected The value to compare against. + * \returns True if the strings match, zero otherwise. + */ +int cstr_eqi(const char* str, const char* expected) +{ + if (str != NULL && expected != NULL) + { + while (*str && *expected) + { + if (tolower(*str) != tolower(*expected)) + { + return 0; + } + + str++; + expected++; + } + + return (*str == *expected); + } + return 0; +} + + /** * Builds a string using printf-style formatting codes. * \param format The format string, which may contain printf-style formatting codes. diff --git a/src/base/cstr.h b/src/base/cstr.h index 27e10d60..9232c6a5 100644 --- a/src/base/cstr.h +++ b/src/base/cstr.h @@ -8,6 +8,7 @@ int cstr_ends_with(const char* str, const char* expected); int cstr_eq(const char* str, const char* expected); +int cstr_eqi(const char* str, const char* expected); char* cstr_format(const char* format, ...); int cstr_starts_with(const char* str, const char* expected); diff --git a/src/base/path.c b/src/base/path.c index 7886676b..a170960a 100644 --- a/src/base/path.c +++ b/src/base/path.c @@ -212,10 +212,9 @@ int path_is_cpp_source(const char* path) return 0; } - _strlwr(ext); for (i = 0; CppFileExtensions[i] != NULL; ++i) { - if (cstr_eq(CppFileExtensions[i], ext)) + if (cstr_eqi(CppFileExtensions[i], ext)) return 1; } diff --git a/src/base/tests/cstr_tests.cpp b/src/base/tests/cstr_tests.cpp index 77d185e3..1302fc44 100644 --- a/src/base/tests/cstr_tests.cpp +++ b/src/base/tests/cstr_tests.cpp @@ -67,6 +67,31 @@ SUITE(cstr) } + /************************************************************************** + * cstr_eqi() tests + **************************************************************************/ + + TEST(CStrEqi_ReturnsTrue_OnMatch) + { + CHECK(cstr_eqi("A string", "a String")); + } + + TEST(CStrEqi_ReturnsFalse_OnMismatch) + { + CHECK(!cstr_eqi("A string", "a different string")); + } + + TEST(CStrEqi_ReturnsFalse_OnNullTarget) + { + CHECK(!cstr_eqi(NULL, "something")); + } + + TEST(CStrEqi_ReturnsFalse_OnNullPattern) + { + CHECK(!cstr_eqi("something", NULL)); + } + + /************************************************************************** * cstr_format() tests **************************************************************************/