History

Allow different names for pragma once

pragma once can now be used with test.h ./test.h and other references to the same file just like gcc/clang. On linux we can use stat and st_ino to check for the same file. On windows the st_ino does not work so we calculate a file hash if the size of the file differs and then compare the hash.

herman ten brugge committed 3 years ago

Commit 30fd24a1 parent 5077d4c5 files · +74 −12Browse files

Unified · Split

5 files
  1. tcc.h +5 −0
  2. tccpp.c +62 −12
  3. tests/tests2/18_include.c +4 −0
  4. tests/tests2/18_include.expect +1 −0
  5. tests/tests2/18_include2.h +2 −0
tcc.h+5−0
@@ -38,6 +38,7 @@ · 37 unmodified lines
3838 #include <fcntl.h>
3939 #include <setjmp.h>
4040 #include <time.h>
41+#include <sys/stat.h>
4142
4243 #ifndef _WIN32
4344 # include <unistd.h>
@@ -716,6 +717,10 @@ typedef struct InlineFunc { · 672 unmodified lines
716717 /* include file cache, used to find files faster and also to eliminate
717718 inclusion if the include file is protected by #ifndef ... #endif */
718719 typedef struct CachedInclude {
720+ struct stat st;
721+#ifdef _WIN32
722+ unsigned long long hash;
723+#endif
719724 int ifndef_macro;
720725 int once;
721726 int hash_next; /* -1 if none */
tccpp.c+62−12
@@ -1607,38 +1607,88 @@ bad_twosharp: · 1606 unmodified lines
16071607 define_push(v, t, tok_str_dup(&tokstr_buf), first);
16081608 }
16091609
1610+#ifdef _WIN32
1611+static unsigned long long calc_file_hash(const char *filename)
1612+{
1613+ unsigned long long hash = 14695981039346656037ull; // FNV_offset_basis;
1614+ FILE *fp = fopen (filename, "rb");
1615+
1616+ if (fp == NULL)
1617+ return 0;
1618+ for (;;) {
1619+ unsigned char temp[IO_BUF_SIZE];
1620+ int i, n = fread(temp, 1, sizeof(temp), fp);
1621+
1622+ if (n <= 0)
1623+ break;
1624+ for (i = 0; i < n; i++)
1625+ hash = hash * 1099511628211ull + temp[i]; // FNV_prime
1626+ }
1627+ fclose(fp);
1628+ if (hash == 0)
1629+ hash = 1;
1630+ return hash;
1631+}
1632+#endif
1633+
16101634 static CachedInclude *search_cached_include(TCCState *s1, const char *filename, int add)
16111635 {
1612− const unsigned char *s;
1613− unsigned int h;
1636+ unsigned int h = 0;
16141637 CachedInclude *e;
16151638 int i;
1616−
1617− h = TOK_HASH_INIT;
1618− s = (unsigned char *) filename;
1619− while (*s) {
1639+ struct stat st;
16201640 #ifdef _WIN32
1621− h = TOK_HASH_FUNC(h, toup(*s));
1622−#else
1623− h = TOK_HASH_FUNC(h, *s);
1641+ unsigned long long hash = 0;
16241642 #endif
1625− s++;
1643+
1644+ /* This is needed for #pragmae once
1645+ * We cannot use stat on windows because st_ino is not set correctly
1646+ * so we calculate a hash of file contents.
1647+ * This also works for hard/soft links as in gcc/clang.
1648+ */
1649+ memset (&st, 0, sizeof(st));
1650+ if (stat (filename, &st))
1651+ goto skip;
1652+ h = st.st_size & (CACHED_INCLUDES_HASH_SIZE - 1);
1653+#ifdef _WIN32
1654+ /* Only calculate file hash if file size same. */
1655+ i = s1->cached_includes_hash[h];
1656+ for(;;) {
1657+ if (i == 0)
1658+ break;
1659+ e = s1->cached_includes[i - 1];
1660+ if (e->st.st_size == st.st_size) {
1661+ if (e->hash == 0)
1662+ e->hash = calc_file_hash(e->filename);
1663+ hash = calc_file_hash(filename);
1664+ break;
1665+ }
1666+ i = e->hash_next;
16261667 }
1627− h &= (CACHED_INCLUDES_HASH_SIZE - 1);
1668+#endif
16281669
16291670 i = s1->cached_includes_hash[h];
16301671 for(;;) {
16311672 if (i == 0)
16321673 break;
16331674 e = s1->cached_includes[i - 1];
1634− if (0 == PATHCMP(e->filename, filename))
1675+#ifdef _WIN32
1676+ if (e->st.st_size == st.st_size && e->hash == hash)
1677+#else
1678+ if (st.st_dev == e->st.st_dev && st.st_ino == e->st.st_ino)
1679+#endif
16351680 return e;
16361681 i = e->hash_next;
16371682 }
1683+skip:
16381684 if (!add)
16391685 return NULL;
16401686
16411687 e = tcc_malloc(sizeof(CachedInclude) + strlen(filename));
1688+ e->st = st;
1689+#ifdef _WIN32
1690+ e->hash = hash;
1691+#endif
16421692 strcpy(e->filename, filename);
16431693 e->ifndef_macro = e->once = 0;
16441694 dynarray_add(&s1->cached_includes, &s1->nb_cached_includes, e);
tests/tests2/18_include.c+4−0
@@ -37,6 +37,10 @@ int main() · 36 unmodified lines
3737 #endif
3838 #endif
3939
40+#include "18_include2.h"
41+#include "./18_include2.h"
42+#include "../tests2/18_include2.h"
43+
4044 return 0;
4145 }
4246
tests/tests2/18_include.expect+1−0
@@ -5,3 +5,4 @@ has_include · 4 unmodified lines
55 has_include
66 has_include_next
77 has_include_next
8+counter 0
tests/tests2/18_include2.h+2−0
@@ -0,0 +1,2 @@
1+#pragma once
2+printf ("counter %d\n", __COUNTER__);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t