From 777fadae95db2fe08227a7d803c07e16fd08ae3e Mon Sep 17 00:00:00 2001 From: "R. Blaine Whittle" Date: Fri, 7 Apr 2017 12:17:10 -0700 Subject: [PATCH 1/3] Added os touchfile and a workaround for vs2010 reloading vs2010 (and above) has an issue where if the vcxproj file isn't modified but the.vcxproj.filters is modified during premake, then VS doesn't notify the user that the project has changed. This can occur if the only change to a project is with the vpaths. Before this fix, the user would be need to manually unload and reload the project to pick up the change. This VS workaround checks for the case where the vcxproj.filters file is modified but the .vcxproj file is not. At which point premake preforms a touch on the .vcxproj file to trigger the IDE. --- modules/vstudio/vs2010.lua | 7 ++- src/base/premake.lua | 39 +++++++++++++++- src/host/os_touchfile.c | 94 ++++++++++++++++++++++++++++++++++++++ src/host/premake.c | 1 + src/host/premake.h | 1 + 5 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 src/host/os_touchfile.c diff --git a/modules/vstudio/vs2010.lua b/modules/vstudio/vs2010.lua index 09d10514..bf939762 100644 --- a/modules/vstudio/vs2010.lua +++ b/modules/vstudio/vs2010.lua @@ -59,7 +59,7 @@ end elseif p.project.isc(prj) or p.project.iscpp(prj) then - p.generate(prj, ".vcxproj", vstudio.vc2010.generate) + local projFileModified = p.generate(prj, ".vcxproj", vstudio.vc2010.generate) -- Skip generation of empty user files local user = p.capture(function() vstudio.vc2010.generateUser(prj) end) @@ -69,7 +69,10 @@ -- Only generate a filters file if the source tree actually has subfolders if tree.hasbranches(project.getsourcetree(prj)) then - p.generate(prj, ".vcxproj.filters", vstudio.vc2010.generateFilters) + if p.generate(prj, ".vcxproj.filters", vstudio.vc2010.generateFilters) == true and projFileModified == false then + -- vs workaround for issue where if only the .filters file is modified, VS doesn't automaticly trigger a reload + p.touch(prj, ".vcxproj") + end end end diff --git a/src/base/premake.lua b/src/base/premake.lua index 93e2015b..1ba52282 100644 --- a/src/base/premake.lua +++ b/src/base/premake.lua @@ -137,6 +137,7 @@ -- +-- Returns a boolean if the file was modified -- Open a file for output, and call a function to actually do the writing. -- Used by the actions to generate workspace and project files. -- @@ -160,22 +161,56 @@ -- make sure output folder exists. local dir = path.getdirectory(fn) - ok, err = os.mkdir(dir) + local ok, err = os.mkdir(dir) if not ok then error(err, 0) end local f, err = os.writefile_ifnotequal(output, fn); - if (f < 0) then + if (f == 0) then + return false -- file not modified + elseif (f < 0) then error(err, 0) elseif (f > 0) then printf("Generated %s...", path.getrelative(os.getcwd(), fn)) + return true -- file modified end end +-- +-- Marks a file as modified without changing its contents +-- +-- @param obj +-- A workspace or project object; will be passed to the callback function. +-- @param ext +-- An optional extension for the generated file, with the leading dot. +-- + + function premake.touch(obj, ext) + local fn = premake.filename(obj, ext) + + -- make sure output folder exists. + local dir = path.getdirectory(fn) + local ok, err = os.mkdir(dir) + if not ok then + error(err, 0) + end + + local f, err = os.touchfile(fn); + + if (f == 0) then + return false -- file marked as modified + elseif (f < 0) then + error(err, 0) + elseif (f > 0) then + return true -- file created + end + end + + --- -- Returns the full path a file generated from any of the project -- objects (project, workspace, rule). diff --git a/src/host/os_touchfile.c b/src/host/os_touchfile.c new file mode 100644 index 00000000..ccdaa9d7 --- /dev/null +++ b/src/host/os_touchfile.c @@ -0,0 +1,94 @@ +/** + * \file os_touchfile.c + * \brief markes a file as modified without changing its contents. + * \author Blizzard Entertainment (contact tvandijck@blizzard.com) + * \author Copyright (c) 2015 Jason Perkins and the Premake project + */ + +#include +#include +#include +#include "premake.h" + +#if PLATFORM_WINDOWS + #include +#else + #include + #include +#endif + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +static int truncate_file(const char* fn) +{ + FILE* file = fopen(fn, "rb"); + size_t size; + file = fopen(fn, "ab"); + if (file == NULL) + { + return FALSE; + } + fseek(file, 0, SEEK_END); + size = ftell(file); + // append a dummy space. There are better ways to do + // a touch, however this is a rather simple + // multiplatform method + if (fwrite(" ", 1, 1, file) != 1) + { + fclose(file); + return FALSE; + } +#if PLATFORM_WINDOWS + if (_chsize(_fileno(file), (long)size) != 0) + { + fclose(file); + return FALSE; + } +#endif + fclose(file); +#if !PLATFORM_WINDOWS + if (truncate(fn, (off_t)size) != 0) + { + return FALSE; + } +#endif + return TRUE; +} + +int os_touchfile(lua_State* L) +{ + FILE* file; + const char* dst = luaL_checkstring(L, 1); + + // if destination exist, mark the file as modified + if (do_isfile(dst)) + { + if (truncate_file(dst)) + { + lua_pushinteger(L, 0); + return 1; + } else { + lua_pushinteger(L, -1); + lua_pushfstring(L, "unable to touch file '%s'", dst); + return 2; + } + } + + file = fopen(dst, "wb"); + if (file != NULL) + { + fclose(file); + + lua_pushinteger(L, 1); + return 1; + } + + lua_pushinteger(L, -1); + lua_pushfstring(L, "unable to create file to '%s'", dst); + return 2; +} diff --git a/src/host/premake.c b/src/host/premake.c index a63e6721..648045f5 100644 --- a/src/host/premake.c +++ b/src/host/premake.c @@ -86,6 +86,7 @@ static const luaL_Reg os_functions[] = { { "stat", os_stat }, { "uuid", os_uuid }, { "writefile_ifnotequal", os_writefile_ifnotequal }, + { "touchfile", os_touchfile }, { "compile", os_compile }, { NULL, NULL } }; diff --git a/src/host/premake.h b/src/host/premake.h index 87c21879..b48a3801 100644 --- a/src/host/premake.h +++ b/src/host/premake.h @@ -140,6 +140,7 @@ int os_rmdir(lua_State* L); int os_stat(lua_State* L); int os_uuid(lua_State* L); int os_writefile_ifnotequal(lua_State* L); +int os_touchfile(lua_State* L); int os_compile(lua_State* L); int string_endswith(lua_State* L); int string_hash(lua_State* L); From 02a591271e9d5c4665d7d2a5ef90b535de6a9d3a Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Tue, 20 Jun 2017 09:53:27 -0700 Subject: [PATCH 2/3] fix call to do_isfile --- src/host/os_touchfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host/os_touchfile.c b/src/host/os_touchfile.c index ccdaa9d7..030ce605 100644 --- a/src/host/os_touchfile.c +++ b/src/host/os_touchfile.c @@ -66,7 +66,7 @@ int os_touchfile(lua_State* L) const char* dst = luaL_checkstring(L, 1); // if destination exist, mark the file as modified - if (do_isfile(dst)) + if (do_isfile(L, dst)) { if (truncate_file(dst)) { From 681c458e31250a6fb87d743022a2d43be6cde018 Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Tue, 20 Jun 2017 09:57:20 -0700 Subject: [PATCH 3/3] Make it support UTF-8 strings, like all other methods. --- src/host/os_touchfile.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/host/os_touchfile.c b/src/host/os_touchfile.c index 030ce605..a3850683 100644 --- a/src/host/os_touchfile.c +++ b/src/host/os_touchfile.c @@ -79,7 +79,20 @@ int os_touchfile(lua_State* L) } } +#if PLATFORM_WINDOWS + wchar_t wide_path[PATH_MAX]; + if (MultiByteToWideChar(CP_UTF8, 0, dst, -1, wide_path, PATH_MAX) == 0) + { + lua_pushinteger(L, -1); + lua_pushstring(L, "unable to encode path"); + return 2; + } + + file = _wfopen(wide_path, L"wb"); +#else file = fopen(dst, "wb"); +#endif + if (file != NULL) { fclose(file); @@ -89,6 +102,6 @@ int os_touchfile(lua_State* L) } lua_pushinteger(L, -1); - lua_pushfstring(L, "unable to create file to '%s'", dst); + lua_pushfstring(L, "unable to open file to '%s'", dst); return 2; }