Completed implementation of location function and project-relative pathing (r479:485)

This commit is contained in:
starkos 2008-08-13 15:25:06 +00:00
parent bcc678cb91
commit 95c23ec10b
28 changed files with 287 additions and 188 deletions

View File

@ -63,44 +63,47 @@ const char* make_get_obj_filename(const char* filename)
const char* make_get_project_makefile(Project prj) const char* make_get_project_makefile(Project prj)
{ {
const char* my_path; const char* my_path;
const char* their_path; int si, sn, in_conflict = 0;
int si, sn;
Session sess = project_get_session(prj); Session sess = project_get_session(prj);
/* get the full makefile path for this project */ /* get the default filename for this project */
my_path = project_get_filename(prj, "Makefile", NULL); my_path = project_get_filename(prj, "Makefile", "");
/* see if any other solution wants to use this same path */ /* see if any other solution wants to use this same path */
sn = session_num_solutions(sess); sn = session_num_solutions(sess);
for (si = 0; si < sn; ++si) for (si = 0; si < sn && !in_conflict; ++si)
{ {
const char* their_path;
int pi, pn; int pi, pn;
Solution sln2 = session_get_solution(sess, si); Solution sln = session_get_solution(sess, si);
their_path = solution_get_filename(sln2, "Makefile", NULL); their_path = solution_get_filename(sln, "Makefile", "");
if (cstr_eq(my_path, their_path)) if (cstr_eq(my_path, their_path))
{ {
/* conflict; use the alternate name */ in_conflict = 1;
my_path = project_get_filename(prj, NULL, ".make");
return my_path;
} }
/* check any projects contained by this solution */ /* check any projects contained by this solution */
pn = solution_num_projects(sln2); pn = solution_num_projects(sln);
for (pi = 0; pi < pn; ++pi) for (pi = 0; pi < pn && !in_conflict; ++pi)
{ {
Project prj2 = solution_get_project(sln2, pi); Project prj2 = solution_get_project(sln, pi);
if (prj != prj2) if (prj != prj2)
{ {
their_path = project_get_filename(prj2, "Makefile", NULL); their_path = project_get_filename(prj2, "Makefile", "");
if (cstr_eq(my_path, their_path)) if (cstr_eq(my_path, their_path))
{ {
/* conflict; use the alternate name */ in_conflict = 1;
}
}
}
}
/* if a conflict was detected use an alternate name */
if (in_conflict)
{
my_path = project_get_filename(prj, NULL, ".make"); my_path = project_get_filename(prj, NULL, ".make");
return my_path;
}
}
}
} }
/* all good */ /* all good */
@ -142,12 +145,12 @@ Strings make_get_project_names(Solution sln)
const char* make_get_solution_makefile(Solution sln) const char* make_get_solution_makefile(Solution sln)
{ {
const char* my_path; const char* my_path;
const char* their_path;
int i, n; int i, n;
Session sess = solution_get_session(sln); Session sess = solution_get_session(sln);
/* get the full makefile path for this solution */ /* get the default file name for this solution */
my_path = solution_get_filename(sln, "Makefile", NULL); my_path = solution_get_filename(sln, "Makefile", "");
/* see if any other solution wants to use this same path */ /* see if any other solution wants to use this same path */
n = session_num_solutions(sess); n = session_num_solutions(sess);
@ -156,7 +159,7 @@ const char* make_get_solution_makefile(Solution sln)
Solution them = session_get_solution(sess, i); Solution them = session_get_solution(sess, i);
if (them != sln) if (them != sln)
{ {
their_path = solution_get_filename(them, "Makefile", NULL); const char* their_path = solution_get_filename(them, "Makefile", "");
if (cstr_eq(my_path, their_path)) if (cstr_eq(my_path, their_path))
{ {
/* conflict; use the alternate name */ /* conflict; use the alternate name */

View File

@ -111,13 +111,15 @@ const char* make_solution_project_rule(Solution sln, Project prj)
char* buffer = buffers_next(); char* buffer = buffers_next();
/* project file paths are specified relative to the solution */ /* project file paths are specified relative to the solution */
const char* sln_path = path_directory(solution_get_filename(sln, NULL, NULL)); const char* sln_file_dir = solution_get_location(sln);
const char* prj_file = make_get_project_makefile(prj); const char* prj_file = make_get_project_makefile(prj);
const char* prj_file_dir = path_directory(prj_file); const char* prj_file_dir = path_directory(prj_file);
const char* prj_file_name = path_filename(prj_file); const char* prj_file_name = path_filename(prj_file);
prj_file_dir = path_relative(sln_path, prj_file_dir);
prj_file_dir = path_relative(sln_file_dir, prj_file_dir);
/* build the rule */
strcpy(buffer, "\t@$(MAKE)"); strcpy(buffer, "\t@$(MAKE)");
if (!cstr_eq(".", prj_file_dir)) if (!cstr_eq(".", prj_file_dir))
{ {

View File

@ -83,7 +83,7 @@ SUITE(action)
TEST_FIXTURE(FxAction, Make_ProjectEntry_InSameDirectory) TEST_FIXTURE(FxAction, Make_ProjectEntry_InSameDirectory)
{ {
project_set_location(prj, ""); project_set_location(prj, solution_get_location(sln));
make_solution_projects(sln, strm); make_solution_projects(sln, strm);
CHECK_EQUAL( CHECK_EQUAL(
"My\\ Project:\n" "My\\ Project:\n"
@ -95,7 +95,7 @@ SUITE(action)
TEST_FIXTURE(FxAction, Make_ProjectEntry_InDifferentDirectory) TEST_FIXTURE(FxAction, Make_ProjectEntry_InDifferentDirectory)
{ {
project_set_location(prj, "My Project"); project_set_location(prj, "Root Folder/Solution Folder/My Project");
make_solution_projects(sln, strm); make_solution_projects(sln, strm);
CHECK_EQUAL( CHECK_EQUAL(
"My\\ Project:\n" "My\\ Project:\n"
@ -112,7 +112,7 @@ SUITE(action)
TEST_FIXTURE(FxAction, Gmake_CleanRule_IsCorrect) TEST_FIXTURE(FxAction, Gmake_CleanRule_IsCorrect)
{ {
project_set_location(prj, ""); project_set_location(prj, solution_get_location(sln));
make_solution_clean_rule(sln, strm); make_solution_clean_rule(sln, strm);
CHECK_EQUAL( CHECK_EQUAL(
"clean:\n" "clean:\n"

View File

@ -40,7 +40,7 @@ struct FxMake
Solution sln = solution_create(); Solution sln = solution_create();
session_add_solution(sess, sln); session_add_solution(sess, sln);
solution_set_name(sln, name); solution_set_name(sln, name);
solution_set_base_dir(sln, "."); solution_set_location(sln, ".");
return sln; return sln;
} }
@ -49,7 +49,7 @@ struct FxMake
Project prj = project_create(); Project prj = project_create();
solution_add_project(sln1, prj); solution_add_project(sln1, prj);
project_set_name(prj, name); project_set_name(prj, name);
project_set_base_dir(prj, "."); project_set_location(prj, ".");
return prj; return prj;
} }
}; };
@ -63,7 +63,7 @@ SUITE(action)
TEST_FIXTURE(FxMake, GetSolutionMakefile_ReturnsMakefile_OnUniqueLocation) TEST_FIXTURE(FxMake, GetSolutionMakefile_ReturnsMakefile_OnUniqueLocation)
{ {
solution_set_location(sln1, "MySolution"); solution_set_location(sln1, "./MySolution");
const char* result = make_get_solution_makefile(sln1); const char* result = make_get_solution_makefile(sln1);
CHECK_EQUAL("./MySolution/Makefile", result); CHECK_EQUAL("./MySolution/Makefile", result);
} }
@ -76,22 +76,22 @@ SUITE(action)
TEST_FIXTURE(FxMake, GetProjectMakefile_ReturnsMakefile_OnUniqueLocation) TEST_FIXTURE(FxMake, GetProjectMakefile_ReturnsMakefile_OnUniqueLocation)
{ {
project_set_location(prj1, "MyProject"); project_set_location(prj1, "./MyProject");
const char* result = make_get_project_makefile(prj1); const char* result = make_get_project_makefile(prj1);
CHECK_EQUAL("./MyProject/Makefile", result); CHECK_EQUAL("./MyProject/Makefile", result);
} }
TEST_FIXTURE(FxMake, GetProjectMakefile_ReturnsDotMake_OnSharedWithSolution) TEST_FIXTURE(FxMake, GetProjectMakefile_ReturnsDotMake_OnSharedWithSolution)
{ {
project_set_location(prj2, "MyProject"); project_set_location(prj2, "./MyProject");
const char* result = make_get_project_makefile(prj1); const char* result = make_get_project_makefile(prj1);
CHECK_EQUAL("./MyProject1.make", result); CHECK_EQUAL("./MyProject1.make", result);
} }
TEST_FIXTURE(FxMake, GetProjectMakefile_ReturnsDotMake_OnSharedWithProject) TEST_FIXTURE(FxMake, GetProjectMakefile_ReturnsDotMake_OnSharedWithProject)
{ {
project_set_location(prj1, "MyProject"); project_set_location(prj1, "./MyProject");
project_set_location(prj2, "MyProject"); project_set_location(prj2, "./MyProject");
const char* result = make_get_project_makefile(prj1); const char* result = make_get_project_makefile(prj1);
CHECK_EQUAL("./MyProject/MyProject1.make", result); CHECK_EQUAL("./MyProject/MyProject1.make", result);
} }

View File

@ -29,6 +29,7 @@ struct FxAction
session_add_solution(sess, sln); session_add_solution(sess, sln);
solution_set_name(sln, "My Solution"); solution_set_name(sln, "My Solution");
solution_set_base_dir(sln, "Root Folder"); solution_set_base_dir(sln, "Root Folder");
solution_set_location(sln, "Root Folder/Solution Folder");
solution_add_config(sln, "Debug DLL"); solution_add_config(sln, "Debug DLL");
solution_add_config(sln, "Release DLL"); solution_add_config(sln, "Release DLL");
@ -36,7 +37,7 @@ struct FxAction
solution_add_project(sln, prj); solution_add_project(sln, prj);
project_set_name(prj, "My Project"); project_set_name(prj, "My Project");
project_set_base_dir(prj, "Root Folder"); project_set_base_dir(prj, "Root Folder");
project_set_location(prj, "Project Folder"); project_set_location(prj, "Root Folder/Project Folder");
project_set_guid(prj, "AE2461B7-236F-4278-81D3-F0D476F9A4C0"); project_set_guid(prj, "AE2461B7-236F-4278-81D3-F0D476F9A4C0");
project_set_language(prj, "c++"); project_set_language(prj, "c++");
project_set_config(prj, "Debug DLL"); project_set_config(prj, "Debug DLL");

View File

@ -34,7 +34,7 @@ SUITE(action)
{ {
vs2002_solution_projects(sln, strm); vs2002_solution_projects(sln, strm);
CHECK_EQUAL( CHECK_EQUAL(
"Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"My Project\", \"Project Folder\\My Project.vcproj\", \"{AE2461B7-236F-4278-81D3-F0D476F9A4C0}\"\n" "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"My Project\", \"..\\Project Folder\\My Project.vcproj\", \"{AE2461B7-236F-4278-81D3-F0D476F9A4C0}\"\n"
"EndProject\n", "EndProject\n",
buffer); buffer);
} }

View File

@ -96,12 +96,7 @@ int vs2002_solution_project_configuration(Solution sln, Stream strm)
*/ */
int vs2002_solution_projects(Solution sln, Stream strm) int vs2002_solution_projects(Solution sln, Stream strm)
{ {
const char* sln_path;
int i, n, z = OKAY; int i, n, z = OKAY;
/* project file paths are specified relative to the solution */
sln_path = path_directory(solution_get_filename(sln, NULL, NULL));
n = solution_num_projects(sln); n = solution_num_projects(sln);
for (i = 0; i < n; ++i) for (i = 0; i < n; ++i)
{ {
@ -110,13 +105,10 @@ int vs2002_solution_projects(Solution sln, Stream strm)
const char* prj_id = project_get_guid(prj); const char* prj_id = project_get_guid(prj);
const char* prj_lang = project_get_language(prj); const char* prj_lang = project_get_language(prj);
const char* prj_ext = vs200x_project_file_extension(prj); const char* prj_ext = vs200x_project_file_extension(prj);
const char* prj_file = project_get_filename(prj, prj_name, prj_ext); const char* prj_file = project_get_filename_relative(prj, prj_name, prj_ext);
const char* tool_id = vs200x_tool_guid(prj_lang); const char* tool_id = vs200x_tool_guid(prj_lang);
/* convert absolute project file name to be relative to solution */
prj_file = path_relative(sln_path, prj_file);
prj_file = path_translate(prj_file, "\\"); prj_file = path_translate(prj_file, "\\");
z |= stream_writeline(strm, "Project(\"{%s}\") = \"%s\", \"%s\", \"{%s}\"", tool_id, prj_name, prj_file, prj_id); z |= stream_writeline(strm, "Project(\"{%s}\") = \"%s\", \"%s\", \"{%s}\"", tool_id, prj_name, prj_file, prj_id);
z |= stream_writeline(strm, "EndProject"); z |= stream_writeline(strm, "EndProject");
} }

View File

@ -236,7 +236,6 @@ char* path_join(const char* leading, const char* trailing)
/* treat nulls like empty paths */ /* treat nulls like empty paths */
leading = (leading != NULL) ? leading : ""; leading = (leading != NULL) ? leading : "";
trailing = (trailing != NULL) ? trailing : "";
if (!trailing) if (!trailing)
{ {

View File

@ -8,6 +8,8 @@
#include "premake.h" #include "premake.h"
#include "strings.h" #include "strings.h"
#include "base/array.h" #include "base/array.h"
#include "base/string.h"
DEFINE_CLASS(Strings) DEFINE_CLASS(Strings)
{ {
@ -50,6 +52,13 @@ Strings strings_create_from_array(const char* items[])
*/ */
void strings_destroy(Strings strs) void strings_destroy(Strings strs)
{ {
int i, n;
n = strings_size(strs);
for (i = 0; i < n; ++i)
{
String item = (String)array_item(strs->contents, i);
string_destroy(item);
}
array_destroy(strs->contents); array_destroy(strs->contents);
free(strs); free(strs);
} }
@ -62,7 +71,8 @@ void strings_destroy(Strings strs)
*/ */
void strings_add(Strings strs, const char* item) void strings_add(Strings strs, const char* item)
{ {
array_add(strs->contents, (void*)item); String str = string_create(item);
array_add(strs->contents, (void*)str);
} }
@ -73,7 +83,13 @@ void strings_add(Strings strs, const char* item)
*/ */
void strings_append(Strings dest, Strings src) void strings_append(Strings dest, Strings src)
{ {
array_append(dest->contents, src->contents); int i, n;
n = strings_size(src);
for (i = 0; i < n; ++i)
{
const char* item = strings_item(src, i);
strings_add(dest, item);
}
} }
@ -85,7 +101,8 @@ void strings_append(Strings dest, Strings src)
*/ */
const char* strings_item(Strings strs, int index) const char* strings_item(Strings strs, int index)
{ {
return (const char*)array_item(strs->contents, index); String item = (String)array_item(strs->contents, index);
return string_cstr(item);
} }
@ -97,7 +114,11 @@ const char* strings_item(Strings strs, int index)
*/ */
void strings_set(Strings strs, int index, const char* item) void strings_set(Strings strs, int index, const char* item)
{ {
array_set(strs->contents, index, (void*)item); String str = (String)array_item(strs->contents, index);
string_destroy(str);
str = string_create(item);
array_set(strs->contents, index, (void*)str);
} }

View File

@ -12,10 +12,10 @@
#include "base/env.h" #include "base/env.h"
struct FieldInfo BlockFieldInfo[] = FieldInfo BlockFieldInfo[] =
{ {
{ "defines", ListField, NULL }, { "defines", ListField, NULL },
{ "objdir", StringField, NULL }, { "objdir", PathField, NULL },
{ "terms", ListField, NULL }, { "terms", ListField, NULL },
{ 0, 0, NULL } { 0, 0, NULL }
}; };

View File

@ -25,7 +25,7 @@ enum BlockField
NumBlockFields NumBlockFields
}; };
extern struct FieldInfo BlockFieldInfo[]; extern FieldInfo BlockFieldInfo[];
DECLARE_CLASS(Block) DECLARE_CLASS(Block)

View File

@ -13,6 +13,7 @@
DEFINE_CLASS(Fields) DEFINE_CLASS(Fields)
{ {
FieldInfo* info;
Strings* values; Strings* values;
int count; int count;
}; };
@ -23,7 +24,7 @@ DEFINE_CLASS(Fields)
* \param info Metadata about the field collection. * \param info Metadata about the field collection.
* \returns A new collection of fields. * \returns A new collection of fields.
*/ */
Fields fields_create(struct FieldInfo* info) Fields fields_create(FieldInfo* info)
{ {
int i; int i;
Fields fields; Fields fields;
@ -31,6 +32,7 @@ Fields fields_create(struct FieldInfo* info)
assert(info); assert(info);
fields = ALLOC_CLASS(Fields); fields = ALLOC_CLASS(Fields);
fields->info = info;
/* figure out how many fields are in the collection */ /* figure out how many fields are in the collection */
for (i = 0; info[i].name != NULL; ++i); for (i = 0; info[i].name != NULL; ++i);
@ -76,6 +78,17 @@ void fields_add_value(Fields fields, int index, const char* value)
} }
/**
* Identify the type of field at the given index.
*/
FieldKind fields_get_kind(Fields fields, int index)
{
assert(fields);
assert(index >= 0 && index < fields->count);
return fields->info[index].kind;
}
/** /**
* Retrieve the value of a string (single value) field. * Retrieve the value of a string (single value) field.
* \returns The field value if set, or NULL. * \returns The field value if set, or NULL.
@ -149,3 +162,13 @@ void fields_set_values(Fields fields, int index, Strings values)
fields->values[index] = values; fields->values[index] = values;
} }
/**
* Return the number of fields in the collection.
*/
int fields_size(Fields fields)
{
assert(fields);
return fields->count;
}

View File

@ -20,12 +20,13 @@
/** /**
* Field types. * Field types.
*/ */
enum FieldKind typedef enum enum_FieldKind
{ {
StringField, StringField, /**< field containing a single, string value */
ListField, ListField, /**< field containing a list of string values */
FilesField FilesField, /**< field containing a list of file names */
}; PathField /**< field containing a file path (directory or file name) */
} FieldKind;
/** /**
@ -39,25 +40,27 @@ typedef int (*FieldValidator)(const char* value);
/** /**
* Metadata about a project object field. * Metadata about a project object field.
*/ */
struct FieldInfo typedef struct struct_FieldInfo
{ {
const char* name; /**< The name of the field. */ const char* name; /**< The name of the field. */
enum FieldKind kind; /**< StringField, ListField, etc. */ FieldKind kind; /**< StringField, ListField, etc. */
FieldValidator validator; /**< The field validation function */ FieldValidator validator; /**< The field validation function */
}; } FieldInfo;
DECLARE_CLASS(Fields) DECLARE_CLASS(Fields)
Fields fields_create(struct FieldInfo* info); Fields fields_create(FieldInfo* info);
void fields_destroy(Fields fields); void fields_destroy(Fields fields);
void fields_add_value(Fields fields, int index, const char* value); void fields_add_value(Fields fields, int index, const char* value);
FieldKind fields_get_kind(Fields fields, int index);
const char* fields_get_value(Fields fields, int index); const char* fields_get_value(Fields fields, int index);
Strings fields_get_values(Fields fields, int index); Strings fields_get_values(Fields fields, int index);
void fields_set_value(Fields fields, int index, const char* value); void fields_set_value(Fields fields, int index, const char* value);
void fields_set_values(Fields fields, int index, Strings values); void fields_set_values(Fields fields, int index, Strings values);
int fields_size(Fields fields);
#endif #endif
/* @} */ /* @} */

View File

@ -17,7 +17,7 @@
#include "base/strings.h" #include "base/strings.h"
struct FieldInfo ProjectFieldInfo[] = FieldInfo ProjectFieldInfo[] =
{ {
{ "basedir", StringField, NULL }, { "basedir", StringField, NULL },
{ "files", FilesField, NULL }, { "files", FilesField, NULL },
@ -87,7 +87,7 @@ void project_destroy(Project prj)
*/ */
const char* project_get_base_dir(Project prj) const char* project_get_base_dir(Project prj)
{ {
return project_get_value(prj, ProjectBaseDirectory); return project_get_value(prj, ProjectBaseDir);
} }
@ -157,7 +157,6 @@ Strings project_get_config_values(Project prj, enum BlockField field)
project_get_values_from_blocks(prj, values, solution_get_blocks(prj->solution), field); project_get_values_from_blocks(prj, values, solution_get_blocks(prj->solution), field);
project_get_values_from_blocks(prj, values, project_get_blocks(prj), field); project_get_values_from_blocks(prj, values, project_get_blocks(prj), field);
return values; return values;
} }
@ -183,7 +182,7 @@ Fields project_get_fields(Project prj)
/** /**
* Get the path to the project output file, using the provided file extension. * Get the path to the project output file, using the provided file name and extension.
* \param prj The project object to query. * \param prj The project object to query.
* \param basename The base filename; if NULL the project name will be used. * \param basename The base filename; if NULL the project name will be used.
* \param ext The file extension to be used on the filename; may be NULL. * \param ext The file extension to be used on the filename; may be NULL.
@ -191,33 +190,38 @@ Fields project_get_fields(Project prj)
*/ */
const char* project_get_filename(Project prj, const char* basename, const char* ext) const char* project_get_filename(Project prj, const char* basename, const char* ext)
{ {
const char* base_dir; const char* location = project_get_location(prj);
const char* location;
const char* directory;
const char* result;
assert(prj);
if (!basename) if (!basename)
{ {
basename = project_get_name(prj); basename = project_get_name(prj);
} }
return path_assemble(location, basename, ext);
if (!ext)
{
ext = "";
}
base_dir = project_get_base_dir(prj);
location = project_get_location(prj);
directory = path_join(base_dir, location);
result = path_assemble(directory, basename, ext);
return result;
} }
/**
* Get the relative path from the solution to the project file, using the
* provided file name and extension.
* \param prj The project object to query.
* \param basename The base filename; if NULL the project name will be used.
* \param ext The file extension to be used on the filename; may be NULL.
* \returns The path to the project file.
*/
const char* project_get_filename_relative(Project prj, const char* basename, const char* ext)
{
const char* sln_location;
const char* abs_filename;
assert(prj);
assert(prj->solution);
sln_location = solution_get_location(prj->solution);
abs_filename = project_get_filename(prj, basename, ext);
return path_relative(sln_location, abs_filename);
}
/** /**
* Retrieve the list of source files associated with a project. * Retrieve the list of source files associated with a project.
*/ */
@ -334,7 +338,7 @@ int project_is_valid_language(const char* language)
*/ */
void project_set_base_dir(Project prj, const char* base_dir) void project_set_base_dir(Project prj, const char* base_dir)
{ {
project_set_value(prj, ProjectBaseDirectory, base_dir); project_set_value(prj, ProjectBaseDir, base_dir);
} }

View File

@ -24,7 +24,7 @@ DECLARE_CLASS(Project)
*/ */
enum ProjectField enum ProjectField
{ {
ProjectBaseDirectory, ProjectBaseDir,
ProjectFiles, ProjectFiles,
ProjectGuid, ProjectGuid,
ProjectLanguage, ProjectLanguage,
@ -33,7 +33,7 @@ enum ProjectField
NumProjectFields NumProjectFields
}; };
extern struct FieldInfo ProjectFieldInfo[]; extern FieldInfo ProjectFieldInfo[];
Project project_create(void); Project project_create(void);
@ -45,6 +45,7 @@ const char* project_get_config(Project prj);
Strings project_get_config_values(Project prj, enum BlockField field); Strings project_get_config_values(Project prj, enum BlockField field);
Fields project_get_fields(Project prj); Fields project_get_fields(Project prj);
const char* project_get_filename(Project prj, const char* basename, const char* ext); const char* project_get_filename(Project prj, const char* basename, const char* ext);
const char* project_get_filename_relative(Project prj, const char* basename, const char* ext);
Strings project_get_files(Project prj); Strings project_get_files(Project prj);
const char* project_get_guid(Project prj); const char* project_get_guid(Project prj);
const char* project_get_language(Project prj); const char* project_get_language(Project prj);

View File

@ -15,7 +15,7 @@
#include "base/strings.h" #include "base/strings.h"
struct FieldInfo SolutionFieldInfo[] = FieldInfo SolutionFieldInfo[] =
{ {
{ "basedir", StringField, NULL }, { "basedir", StringField, NULL },
{ "configurations", ListField, NULL }, { "configurations", ListField, NULL },
@ -101,7 +101,7 @@ void solution_add_project(Solution sln, Project prj)
*/ */
const char* solution_get_base_dir(Solution sln) const char* solution_get_base_dir(Solution sln)
{ {
return solution_get_value(sln, SolutionBaseDirectory); return solution_get_value(sln, SolutionBaseDir);
} }
@ -158,29 +158,12 @@ Fields solution_get_fields(Solution sln)
*/ */
const char* solution_get_filename(Solution sln, const char* basename, const char* ext) const char* solution_get_filename(Solution sln, const char* basename, const char* ext)
{ {
const char* base_dir; const char* location = solution_get_location(sln);
const char* location;
const char* directory;
const char* result;
assert(sln);
if (!basename) if (!basename)
{ {
basename = solution_get_name(sln); basename = solution_get_name(sln);
} }
return path_assemble(location, basename, ext);
if (!ext)
{
ext = "";
}
base_dir = solution_get_base_dir(sln);
location = solution_get_location(sln);
directory = path_join(base_dir, location);
result = path_assemble(directory, basename, ext);
return result;
} }
@ -273,7 +256,7 @@ int solution_num_projects(Solution sln)
*/ */
void solution_set_base_dir(Solution sln, const char* base_dir) void solution_set_base_dir(Solution sln, const char* base_dir)
{ {
solution_set_value(sln, SolutionBaseDirectory, base_dir); solution_set_value(sln, SolutionBaseDir, base_dir);
} }

View File

@ -25,7 +25,7 @@ DECLARE_CLASS(Solution)
*/ */
enum SolutionField enum SolutionField
{ {
SolutionBaseDirectory, SolutionBaseDir,
SolutionConfigurations, SolutionConfigurations,
SolutionLanguage, SolutionLanguage,
SolutionLocation, SolutionLocation,
@ -33,7 +33,7 @@ enum SolutionField
NumSolutionFields NumSolutionFields
}; };
extern struct FieldInfo SolutionFieldInfo[]; extern FieldInfo SolutionFieldInfo[];
Solution solution_create(void); Solution solution_create(void);

View File

@ -21,12 +21,16 @@ struct FxProject
FxProject() FxProject()
{ {
sln = solution_create(); sln = solution_create();
solution_set_name(sln, "MySolution");
solution_set_location(sln, "/BaseDir/MySolution");
prj = project_create(); prj = project_create();
solution_add_project(sln, prj);
project_set_name(prj, "MyProject");
} }
~FxProject() ~FxProject()
{ {
project_destroy(prj);
solution_destroy(sln); solution_destroy(sln);
} }
}; };
@ -44,21 +48,18 @@ SUITE(project)
* Filename tests * Filename tests
**********************************************************************/ **********************************************************************/
TEST_FIXTURE(FxProject, GetFilename_ReturnsFullPath_OnNoLocation) TEST_FIXTURE(FxProject, GetFilenameRel_ReturnsCorrectPath_OnSameDir)
{ {
project_set_name(prj, "MyProject"); project_set_location(prj, "/BaseDir/MySolution");
project_set_base_dir(prj, "/BaseDir"); const char* filename = project_get_filename_relative(prj, NULL, ".xyz");
const char* filename = project_get_filename(prj, NULL, ".xyz"); CHECK_EQUAL("MyProject.xyz", filename);
CHECK_EQUAL("/BaseDir/MyProject.xyz", filename);
} }
TEST_FIXTURE(FxProject, GetFilename_ReturnsFullPath_OnLocation) TEST_FIXTURE(FxProject, GetFilenameRel_ReturnsCorrectPath_OnDifferentDir)
{ {
project_set_name(prj, "MyProject"); project_set_location(prj, "/BaseDir/MyProject");
project_set_base_dir(prj, "/BaseDir"); const char* filename = project_get_filename_relative(prj, NULL, ".xyz");
project_set_location(prj, "Location"); CHECK_EQUAL("../MyProject/MyProject.xyz", filename);
const char* filename = project_get_filename(prj, NULL, ".xyz");
CHECK_EQUAL("/BaseDir/Location/MyProject.xyz", filename);
} }
@ -101,15 +102,8 @@ SUITE(project)
* Solution tests * Solution tests
**********************************************************************/ **********************************************************************/
TEST_FIXTURE(FxProject, GetSolution_ReturnsNull_OnStartup)
{
Solution result = project_get_solution(prj);
CHECK(result == NULL);
}
TEST_FIXTURE(FxProject, SetSolution_CanRoundtrip) TEST_FIXTURE(FxProject, SetSolution_CanRoundtrip)
{ {
project_set_solution(prj, sln);
CHECK(sln == project_get_solution(prj)); CHECK(sln == project_get_solution(prj));
} }

View File

@ -75,28 +75,6 @@ SUITE(project)
} }
/**********************************************************************
* Filename tests
**********************************************************************/
TEST_FIXTURE(FxSolution, GetFilename_ReturnsFullPath_OnNoLocation)
{
solution_set_name(sln, "MySolution");
solution_set_base_dir(sln, "/BaseDir");
const char* filename = solution_get_filename(sln, NULL, ".xyz");
CHECK_EQUAL("/BaseDir/MySolution.xyz", filename);
}
TEST_FIXTURE(FxSolution, GetFilename_ReturnsFullPath_OnLocation)
{
solution_set_name(sln, "MySolution");
solution_set_base_dir(sln, "/BaseDir");
solution_set_location(sln, "Location");
const char* filename = solution_get_filename(sln, NULL, ".xyz");
CHECK_EQUAL("/BaseDir/Location/MySolution.xyz", filename);
}
/********************************************************************** /**********************************************************************
* Project containment tests * Project containment tests
**********************************************************************/ **********************************************************************/

View File

@ -10,10 +10,10 @@
#include "base/error.h" #include "base/error.h"
static int fn_accessor_object_has_field(struct FieldInfo* fields, const char* field_name); static int fn_accessor_object_has_field(FieldInfo* fields, const char* field_name);
static int fn_accessor_register(lua_State* L, struct FieldInfo* fields); static int fn_accessor_register(lua_State* L, FieldInfo* fields);
static int fn_accessor_register_field(lua_State* L, struct FieldInfo* field); static int fn_accessor_register_field(lua_State* L, FieldInfo* field);
static void fn_accessor_append_value(lua_State* L, struct FieldInfo* field, int tbl, int idx); static void fn_accessor_append_value(lua_State* L, FieldInfo* field, int tbl, int idx);
/** /**
@ -37,7 +37,7 @@ int fn_accessor_register_all(lua_State* L)
* Register the accessor functions for a particular set of fields. * Register the accessor functions for a particular set of fields.
* \returns OKAY if successful. * \returns OKAY if successful.
*/ */
static int fn_accessor_register(lua_State* L, struct FieldInfo* fields) static int fn_accessor_register(lua_State* L, FieldInfo* fields)
{ {
int i, z = OKAY; int i, z = OKAY;
@ -54,7 +54,7 @@ static int fn_accessor_register(lua_State* L, struct FieldInfo* fields)
* Register a single accessor function. * Register a single accessor function.
* \returns OKAY if successful. * \returns OKAY if successful.
*/ */
static int fn_accessor_register_field(lua_State* L, struct FieldInfo* field) static int fn_accessor_register_field(lua_State* L, FieldInfo* field)
{ {
int container_type, z; int container_type, z;
@ -84,7 +84,7 @@ static int fn_accessor_register_field(lua_State* L, struct FieldInfo* field)
* Determine if a field list contains a field with a particular name. * Determine if a field list contains a field with a particular name.
* \returns True if the field is contained by the list. * \returns True if the field is contained by the list.
*/ */
static int fn_accessor_object_has_field(struct FieldInfo* fields, const char* field_name) static int fn_accessor_object_has_field(FieldInfo* fields, const char* field_name)
{ {
int i; int i;
for (i = 0; fields[i].name != NULL; ++i) for (i = 0; fields[i].name != NULL; ++i)
@ -104,7 +104,7 @@ static int fn_accessor_object_has_field(struct FieldInfo* fields, const char* fi
*/ */
int fn_accessor(lua_State* L) int fn_accessor(lua_State* L)
{ {
struct FieldInfo* field; FieldInfo* field;
int container_type; int container_type;
/* get the required container object */ /* get the required container object */
@ -115,12 +115,12 @@ int fn_accessor(lua_State* L)
} }
/* get information about the field being accessed */ /* get information about the field being accessed */
field = (struct FieldInfo*)lua_touserdata(L, lua_upvalueindex(2)); field = (FieldInfo*)lua_touserdata(L, lua_upvalueindex(2));
/* if a value is provided, set the field */ /* if a value is provided, set the field */
if (lua_gettop(L) > 1) if (lua_gettop(L) > 1)
{ {
if (field->kind == StringField) if (field->kind == StringField || field->kind == PathField)
{ {
fn_accessor_set_string_value(L, field); fn_accessor_set_string_value(L, field);
} }
@ -140,7 +140,7 @@ int fn_accessor(lua_State* L)
* Sets a string field to the value on the bottom of the Lua stack. * Sets a string field to the value on the bottom of the Lua stack.
* \returns OKAY if successful. * \returns OKAY if successful.
*/ */
int fn_accessor_set_string_value(lua_State* L, struct FieldInfo* field) int fn_accessor_set_string_value(lua_State* L, FieldInfo* field)
{ {
/* can't set lists to simple fields */ /* can't set lists to simple fields */
if (lua_istable(L, 1)) if (lua_istable(L, 1))
@ -171,7 +171,7 @@ int fn_accessor_set_string_value(lua_State* L, struct FieldInfo* field)
* Appends the value or list at the bottom of the Lua stack to the specified list field. * Appends the value or list at the bottom of the Lua stack to the specified list field.
* \returns OKAY if successful. * \returns OKAY if successful.
*/ */
int fn_accessor_set_list_value(lua_State* L, struct FieldInfo* field) int fn_accessor_set_list_value(lua_State* L, FieldInfo* field)
{ {
/* get the current value of the field */ /* get the current value of the field */
lua_getfield(L, -1, field->name); lua_getfield(L, -1, field->name);
@ -194,7 +194,7 @@ int fn_accessor_set_list_value(lua_State* L, struct FieldInfo* field)
* \param tbl The table to contain the values. * \param tbl The table to contain the values.
* \param idx The value to add to the table. * \param idx The value to add to the table.
*/ */
static void fn_accessor_append_value(lua_State* L, struct FieldInfo* field, int tbl, int idx) static void fn_accessor_append_value(lua_State* L, FieldInfo* field, int tbl, int idx)
{ {
int i, n; int i, n;

View File

@ -13,7 +13,7 @@
*/ */
int fn_configurations(lua_State* L) int fn_configurations(lua_State* L)
{ {
struct FieldInfo* field; FieldInfo* field;
if (!script_internal_get_active_object(L, SolutionObject, IS_REQUIRED)) if (!script_internal_get_active_object(L, SolutionObject, IS_REQUIRED))
{ {
@ -29,7 +29,7 @@ int fn_configurations(lua_State* L)
lua_pop(L, 1); lua_pop(L, 1);
/* get information about the field being accessed */ /* get information about the field being accessed */
field = (struct FieldInfo*)lua_touserdata(L, lua_upvalueindex(2)); field = (FieldInfo*)lua_touserdata(L, lua_upvalueindex(2));
/* if a value is provided, set the field */ /* if a value is provided, set the field */
if (lua_gettop(L) > 1) if (lua_gettop(L) > 1)

View File

@ -56,7 +56,7 @@ int fn_project(lua_State* L)
/* set the base directory */ /* set the base directory */
lua_pushstring(L, script_internal_script_dir(L)); lua_pushstring(L, script_internal_script_dir(L));
lua_setfield(L, -2, ProjectFieldInfo[ProjectBaseDirectory].name); lua_setfield(L, -2, ProjectFieldInfo[ProjectBaseDir].name);
/* set a default GUID */ /* set a default GUID */
lua_pushstring(L, guid_create()); lua_pushstring(L, guid_create());

View File

@ -38,7 +38,7 @@ int fn_solution(lua_State* L)
/* set the base directory */ /* set the base directory */
lua_pushstring(L, script_internal_script_dir(L)); lua_pushstring(L, script_internal_script_dir(L));
lua_setfield(L, -2, SolutionFieldInfo[SolutionBaseDirectory].name); lua_setfield(L, -2, SolutionFieldInfo[SolutionBaseDir].name);
/* create an empty list of projects */ /* create an empty list of projects */
lua_newtable(L); lua_newtable(L);

View File

@ -29,7 +29,8 @@ int script_internal_create_block(lua_State* L)
/* set all list-type configuration block values to empty tables */ /* set all list-type configuration block values to empty tables */
for (i = 0; i < NumBlockFields; ++i) for (i = 0; i < NumBlockFields; ++i)
{ {
if (BlockFieldInfo[i].kind != StringField) int kind = BlockFieldInfo[i].kind;
if (kind != StringField && kind != PathField)
{ {
lua_newtable(L); lua_newtable(L);
lua_setfield(L, -2, BlockFieldInfo[i].name); lua_setfield(L, -2, BlockFieldInfo[i].name);
@ -184,14 +185,14 @@ const char* script_internal_script_dir(lua_State* L)
* \param L The Lua state. * \param L The Lua state.
* \param fields The list of object fields. * \param fields The list of object fields.
*/ */
void script_internal_populate_object(lua_State* L, struct FieldInfo* fields) void script_internal_populate_object(lua_State* L, FieldInfo* fields)
{ {
struct FieldInfo* field; FieldInfo* field;
/* set all list-type configuration values to empty tables */ /* set all list-type configuration values to empty tables */
for (field = fields; field->name != NULL; ++field) for (field = fields; field->name != NULL; ++field)
{ {
if (field->kind != StringField) if (field->kind != StringField && field->kind != PathField)
{ {
lua_newtable(L); lua_newtable(L);
lua_setfield(L, -2, field->name); lua_setfield(L, -2, field->name);

View File

@ -40,12 +40,12 @@ int script_internal_create_block(lua_State* L);
int script_internal_get_active_object(lua_State* L, enum ObjectType type, int is_required); int script_internal_get_active_object(lua_State* L, enum ObjectType type, int is_required);
void script_internal_set_active_object(lua_State* L, enum ObjectType type); void script_internal_set_active_object(lua_State* L, enum ObjectType type);
const char* script_internal_script_dir(lua_State* L); const char* script_internal_script_dir(lua_State* L);
void script_internal_populate_object(lua_State* L, struct FieldInfo* fields); void script_internal_populate_object(lua_State* L, FieldInfo* fields);
/* Generic project object field getter/setter API */ /* Generic project object field getter/setter API */
int fn_accessor_register_all(lua_State* L); int fn_accessor_register_all(lua_State* L);
int fn_accessor_set_string_value(lua_State* L, struct FieldInfo* field); int fn_accessor_set_string_value(lua_State* L, FieldInfo* field);
int fn_accessor_set_list_value(lua_State* L, struct FieldInfo* field); int fn_accessor_set_list_value(lua_State* L, FieldInfo* field);
/* script function handlers */ /* script function handlers */
int fn_accessor(lua_State* L); int fn_accessor(lua_State* L);

View File

@ -28,6 +28,7 @@ struct FxUnloadProject
"solution('MySolution');" "solution('MySolution');"
" configurations {'Debug','Release'};" " configurations {'Debug','Release'};"
"prj = project('MyProject');" "prj = project('MyProject');"
" prj.basedir = '/basedir';"
" guid '0C202E43-B9AF-4972-822B-5A42F0BF008C';" " guid '0C202E43-B9AF-4972-822B-5A42F0BF008C';"
" language 'c++';" " language 'c++';"
" files { 'Hello.cpp', 'Goodbye.cpp' };" " files { 'Hello.cpp', 'Goodbye.cpp' };"
@ -55,7 +56,7 @@ SUITE(unload)
{ {
unload_project(L, prj); unload_project(L, prj);
const char* result = project_get_base_dir(prj); const char* result = project_get_base_dir(prj);
CHECK_EQUAL("(string)", result); CHECK_EQUAL("/basedir", result);
} }
TEST_FIXTURE(FxUnloadProject, UnloadProject_UnloadsFiles) TEST_FIXTURE(FxUnloadProject, UnloadProject_UnloadsFiles)
@ -69,6 +70,18 @@ SUITE(unload)
} }
} }
TEST_FIXTURE(FxUnloadProject, UnloadProject_RepointsFiles_OnLocation)
{
script_run_string(script, "location 'build'; return prj");
unload_project(L, prj);
Strings files = project_get_files(prj);
CHECK(strings_size(files) == 2);
if (strings_size(files) == 2) {
CHECK_EQUAL("../Hello.cpp", strings_item(files, 0));
CHECK_EQUAL("../Goodbye.cpp", strings_item(files, 1));
}
}
TEST_FIXTURE(FxUnloadProject, UnloadProject_SetsGuid) TEST_FIXTURE(FxUnloadProject, UnloadProject_SetsGuid)
{ {
unload_project(L, prj); unload_project(L, prj);
@ -82,5 +95,20 @@ SUITE(unload)
const char* result = project_get_language(prj); const char* result = project_get_language(prj);
CHECK_EQUAL("c++", result); CHECK_EQUAL("c++", result);
} }
TEST_FIXTURE(FxUnloadProject, UnloadProject_SetsLocation_OnUnsetLocation)
{
unload_project(L, prj);
const char* result = project_get_location(prj);
CHECK_EQUAL("/basedir", result);
}
TEST_FIXTURE(FxUnloadProject, UnloadProject_SetsLocation_OnSetLocation)
{
script_run_string(script, "location 'location'; return prj");
unload_project(L, prj);
const char* result = project_get_location(prj);
CHECK_EQUAL("/basedir/location", result);
}
} }

View File

@ -27,6 +27,8 @@ struct FxUnloadSolution
script_run_string(script, script_run_string(script,
"sln = solution('MySolution');" "sln = solution('MySolution');"
" configurations { 'Debug', 'Release' };" " configurations { 'Debug', 'Release' };"
" sln.basedir = '/basedir';"
" location 'location';"
"return sln"); "return sln");
} }
@ -51,7 +53,7 @@ SUITE(unload)
{ {
unload_solution(L, sln); unload_solution(L, sln);
const char* result = solution_get_base_dir(sln); const char* result = solution_get_base_dir(sln);
CHECK_EQUAL("(string)", result); CHECK_EQUAL("/basedir", result);
} }
TEST_FIXTURE(FxUnloadSolution, UnloadSolution_SetsConfigurations) TEST_FIXTURE(FxUnloadSolution, UnloadSolution_SetsConfigurations)
@ -61,5 +63,12 @@ SUITE(unload)
CHECK_EQUAL("Debug", solution_get_config(sln, 0)); CHECK_EQUAL("Debug", solution_get_config(sln, 0));
CHECK_EQUAL("Release", solution_get_config(sln, 1)); CHECK_EQUAL("Release", solution_get_config(sln, 1));
} }
TEST_FIXTURE(FxUnloadSolution, UnloadSolution_SetsLocation)
{
unload_solution(L, sln);
const char* result = solution_get_location(sln);
CHECK_EQUAL("/basedir/location", result);
}
} }

View File

@ -7,10 +7,12 @@
#include <assert.h> #include <assert.h>
#include "premake.h" #include "premake.h"
#include "script/script_internal.h" #include "script/script_internal.h"
#include "base/path.h"
static int unload_blocks(lua_State* L, struct UnloadFuncs* funcs, Blocks blocks); static int unload_blocks(lua_State* L, struct UnloadFuncs* funcs, Blocks blocks);
static int unload_projects(lua_State* L, struct UnloadFuncs* funcs, Solution sln); static int unload_projects(lua_State* L, struct UnloadFuncs* funcs, Solution sln);
static int unload_repoint_paths(Fields fields, int base_dir_idx, int location_idx);
/** /**
@ -126,7 +128,7 @@ static int unload_blocks(lua_State* L, struct UnloadFuncs* funcs, Blocks blocks)
} }
int unload_fields(lua_State* L, Fields fields, struct FieldInfo* info) int unload_fields(lua_State* L, Fields fields, FieldInfo* info)
{ {
const char* value; const char* value;
int fi; int fi;
@ -179,7 +181,10 @@ int unload_fields(lua_State* L, Fields fields, struct FieldInfo* info)
*/ */
int unload_solution(lua_State* L, Solution sln) int unload_solution(lua_State* L, Solution sln)
{ {
return unload_fields(L, solution_get_fields(sln), SolutionFieldInfo); Fields fields = solution_get_fields(sln);
int z = unload_fields(L, fields, SolutionFieldInfo);
unload_repoint_paths(fields, SolutionBaseDir, SolutionLocation);
return z;
} }
@ -191,7 +196,10 @@ int unload_solution(lua_State* L, Solution sln)
*/ */
int unload_project(lua_State* L, Project prj) int unload_project(lua_State* L, Project prj)
{ {
return unload_fields(L, project_get_fields(prj), ProjectFieldInfo); Fields fields = project_get_fields(prj);
int z = unload_fields(L, fields, ProjectFieldInfo);
unload_repoint_paths(fields, ProjectBaseDir, ProjectLocation);
return z;
} }
@ -205,3 +213,52 @@ int unload_block(lua_State* L, Block blk)
{ {
return unload_fields(L, block_get_fields(blk), BlockFieldInfo); return unload_fields(L, block_get_fields(blk), BlockFieldInfo);
} }
/**
* Walks a list of fields and repoints all paths to be relative to
* base_directory/location. Once this is done, all paths will end up
* relative to the generated project or solution file.
* \param fields The list of fields to repoint.
* \param base_dir_idx The index of the BaseDir field in the field list.
* \param location_idx The index of the Location field in the field list.
*/
int unload_repoint_paths(Fields fields, int base_dir_idx, int location_idx)
{
const char* base_dir;
const char* location;
int fi, fn;
/* first I have to update the Location field; this is the absolute path that
* I will base all the other relative paths upon */
base_dir = fields_get_value(fields, base_dir_idx);
location = path_join(base_dir, fields_get_value(fields, location_idx));
fields_set_value(fields, location_idx, location);
/* now I can can for other pathed fields and repoint them */
fn = fields_size(fields);
for (fi = 0; fi < fn; ++fi)
{
/* only repoint pathed fields */
int kind = fields_get_kind(fields, fi);
if (kind == FilesField || kind == PathField)
{
/* enumerate all values of the field */
int vi, vn;
Strings values = fields_get_values(fields, fi);
vn = strings_size(values);
for (vi = 0; vi < vn; ++vi)
{
const char* value = strings_item(values, vi);
const char* abs_path = path_join(base_dir, value);
const char* rel_path = path_relative(location, abs_path);
strings_set(values, vi, rel_path);
}
}
}
return OKAY;
}