Tk Source Code

View Ticket
Login
Ticket UUID: 6a9bae5e8da5cdbe1dab68dd84ee1f35a9f0dca6
Title: Directory library/demos unexpectedly embedded into tcl9tk91.dll
Type: Bug Version: 9+
Submitter: nemethi Created on: 2026-02-16 12:55:58
Subsystem: 85. Win Build Assigned To: jan.nijtmans
Priority: 5 Medium Severity: Minor
Status: Closed Last Modified: 2026-02-19 15:12:24
Resolution: Fixed Closed By: oehhar
    Closed on: 2026-02-19 15:12:24
Description:

Line 733 of the Tk trunk file win/Makefile.in reads:

@$(RMDIR) $(TK_VFS_PATH)/demos

This makes sure that when building Tk with gcc, the directory library/demos won't be contained in the Tk library zip file libtk9.1a1.zip.

On the other hand, when building Tk with Visual C, currently the directory library/demos is contained in libtk9.1a1.zip, and hence in tcl9tk91.dll, too.  This unexpected discrepancy should be fixed by inserting

@$(RMDIR) "$(LIBTKVFS)\$(TKSCRIPTZIPTOP)\demos"

just after line 497 of the Visual C makefile makefile.vc.  I think this was simply forgotten when adapting the file makefile.vc to Tk 9+.

The same fix should be done for core-9-0-branch, too.

User Comments: oehhar added on 2026-02-19 15:12:24:

If we wait for Ashoks opinion, shouldn't we keep the ticket open? Harald


oehhar added on 2026-02-18 09:39:24:
Great, thanks.

jan.nijtmans added on 2026-02-17 20:59:03:

Agreed!

> With my proposal to change the definition of RMDIR and MKDIR, there would be no need for using "file delete" instead of $(RMDIR).

Indeed. Still I prefer to keep "file delete" for now for 2 reasons. 1) If Tk picks up an old rules.vc it wouldn't work. 2) Do rd/md work in all environments, even WINE (for example)? We already have to start tclsh anyway, so doing an extra action doesn't cost much.

As follow-up action, I would like to kill the "if exists ..." before the RMDIR/MKDIR's in the makefile.vc. But for that I prefer to hear Ashok's opinion first.


oehhar added on 2026-02-17 18:40:18:

Jans fix is effective.

Nevertheless, I find it more straight-forward to fix $(RMDIR), as proposed by Csaba.

This requires to also apply the patch to TCL, as rules.vc is taken from Tcl, if present there.

This is now in Tcl ticket be40b736, Tcl Checkin b1c564e3.

The same rules.vc is now in commit [acc3cd97] of branch [6a9bae5e-demo-dist-nmake].

Jan, what do you think ?

Thanks for all, Harald


nemethi (claiming to be Csaba Nemethi) added on 2026-02-17 17:28:39:
Harald and Jan, many thanks for all your work!  I haven't yet had time to test the latest trunk version, but I wanted to make two remarks:

1. makefile.vc includes rules-ext.vc, which in turn includes rules.vc.  The latter defines RMDIR and MKDIR as follows:

  RMDIR   = rmdir /S /Q
  ...
  MKDIR   = mkdir

This is dangerous, because rmdir and mkdir are not only Window (originally DOS) commands, but they are also present in cygwin and msys/mingw, being that these emulate a part of a Unix environment.  And the cygwin commands seem to have precedence over the commands of the same name of Windows. 

IMHO, the above definitions should be replaced with

  RMDIR   = rd /S /Q
  ...
  MKDIR   = md

This would be better because rd and md are not present in cygwin and msys/mingw, thus no command-related ambiguities could happen any longer.

2. Even with $(RMDIR) replaced by "file delete", the file makefile.vc contains two more occurrences of $(RMDIR).  With my proposal to change the definition of RMDIR and MKDIR, there would be no need for using "file delete" instead of $(RMDIR).

jan.nijtmans added on 2026-02-17 16:58:40:

> In addition, it would be beneficial to find out *why* $(RMDIR) does not work. I only see the error message:

It looks like the GITHUB CI environment has the mingw "rmdir", not the MSVC version. Therefore the /S and /Q options are not recognized.

Looking again, I think there were too many quotes. Does [041375daf82b3a9d|this] fix it? I have a new laptop without any Visual Studio (and I don't have the rights to install it), so I cannot test it myself (other than push it to GITHUB)


oehhar added on 2026-02-17 16:15:52:

Thanks for the action. I tested the current main branch.

Compilation passes well:

Building Tk library zip file
C:\test\fossil\tk\main\win\Release_AMD64_VC1944\tcl9tk91.dll
C:\test\fossil\tk\main\win\Release_AMD64_VC1944\libtk9.1a1.zip
        1 Datei(en) kopiert.

Then, I install and name a copy of "tcl9tk91.dll" to "tcl9tk91.zip". Then, I open the zip file using 7zip.

The file still contains the folder "tk_library\demos" with all its content.

So, it does not work for me, sorry.

In addition, it would be beneficial to find out *why* $(RMDIR) does not work. I only see the error message:

/usr/bin/rmdir: `/S': Permission denied
/usr/bin/rmdir: `/Q': No such file or directory
/usr/bin/rmdir: `C:\\test\\fossil\\tk\\6a9bae5e-demo-dist-nmake\\win\\Release_AMD64_VC1944\\libtk.vfs\\tk_library\\demos': Directory not empty
NMAKE : fatal error U1077: "rmdir /S /Q "C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\libtk.vfs\t
k_library\demos"": Rückgabe-Code "0x1"

It says, that "/usr/bin/rmdir" treats "/S" and "/Q" as files instead of options. Then, the folder is not deleted due to not empty (e.g. /Q and /S are not taken into account).

I don't know, why "/usr/bin/rmdir" is used. This is a unix path and not a WIndows path.

May it happen, that the Cygwin "rmdir" is picked?

In cygwin:


$ rmdir --help
Usage: rmdir [OPTION]... DIRECTORY...
Remove the DIRECTORY(ies), if they are empty.

      --ignore-fail-on-non-empty
                  ignore each failure that is solely because a directory
                    is non-empty
  -p, --parents   remove DIRECTORY and its ancestors; e.g., 'rmdir -p a/b/c' is
                    similar to 'rmdir a/b/c a/b a'
  -v, --verbose   output a diagnostic for every directory processed
      --help     display this help and exit
      --version  output version information and exit

GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Report any translation bugs to <https://translationproject.org/team/>
Full documentation <https://www.gnu.org/software/coreutils/rmdir>
or available locally via: info '(coreutils) rmdir invocation'
$ which rmdir
/usr/bin/rmdir

The used parameters are aparently for the Windows version. In cmd.exe:

rmdir /?
Entfernt (löscht) ein Verzeichnis.

RMDIR [/S] [/Q] [Laufwerk:]Pfad
RD [/S] [/Q] [Laufwerk:]Pfad

    /S  Löscht alle Verzeichnisse und Dateien im angegebenen Verzeichnis
        zusätzlich zu dem Verzeichnis selbst. Wird verwendet, um ganze
        Verzeichnisbäume zu löschen.

    /Q  Keine Nachfrage, ob die Verzeichnisbäume mit /S entfernt werden
        sollen.

This may IMHO explain the issue.

This would also explain, why we two see it and Csaba not.

I don't have a computer without "Cygwin" here.

When I look to my native prompt path, I don't see the term string "cygwin".

When I search my tk win directory for "cygwin", I get the following match:

--win\configure.ac--
# The following define is needed when building with Cygwin since newer
# versions of autoconf incorrectly set SHELL to /bin/bash instead of
# /bin/sh. The bash shell seems to suffer from some strange failures.
SHELL=/bin/sh

If I search for the definition of RMDIR, I get:

win\Makefile.in
Row 198: RMDIR		= rm -rf
win\rules.vc
Row  144: RMDIR	= rmdir /S /Q

Sorry, no clueue here...

Thanks for all, Harald


jan.nijtmans added on 2026-02-17 12:54:03:

I think [3afabbd304f73c2d|this] should fix it (for both shared and static builds ....). @harald, can you double-check?


jan.nijtmans added on 2026-02-17 11:16:00:

You are right, Harald! It doesn't work. Working on it ....


oehhar added on 2026-02-17 10:49:23:

Csaba, thanks, great !

The proposal is now in commit [81438e19] starting branch [6a9bae5e-demo-dist-nmake].

Here is a test excerp:

make -f makefile.vc TCLDIR=C:\test\fossil\tcl\main

Microsoft (R) Program Maintenance Utility, Version 14.44.35222.0
Copyright (C) Microsoft Corporation. Alle Rechte vorbehalten.

*** Using C:\test\fossil\tcl\main\win\rules.vc

C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win>echo 9,1,0,0  1>>versions.vc
*** Building against Tcl at 'C:\test\fossil\tcl\main'
*** Intermediate directory will be 'C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\tk_Dynamic'
*** Output directory will be 'C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944'
*** Installation, if selected, will be in 'C:\Tcl'
*** Suffix for binaries will be ''
*** Compiler version 1944. Target AMD64, host AMD64.
*** Dependency rules are not being used.
...
        link -nologo -machine:AMD64  -ltcg -release -opt:ref -opt:icf,3 -nodefaultlib:ucrt.lib -dll -out:C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\tcl9tk91.dll kernel32.lib advapi32.lib netapi32.lib gdi32.lib user32.lib userenv.lib winspool.lib shell32.lib ole32.lib uuid.lib oleacc.lib ucrt.lib "C:\test\fossil\tcl\main\win\Release_AMD64_VC1944\tclstub.lib" "C:\test\fossil\tcl\main\win\Release_AMD64_VC1944\tcl91.lib"  @C:\Users\oehhar\AppData\Local\Temp\nm7B5A.tmp
   Bibliothek "C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\tcl9tk91.lib" und Objekt "C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\tcl9tk91.exp" werden erstellt.
Code wird generiert.
Codegenerierung ist abgeschlossen.
        if exist C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\tcl9tk91.dll.manifest mt -nologo -manifest C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\tcl9tk91.dll.manifest -outputresource:C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\tcl9tk91.dll;2
        link -nologo -machine:AMD64  -ltcg -release -opt:ref -opt:icf,3 -nodefaultlib:ucrt.lib -subsystem:windows -out:C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\wish91.exe kernel32.lib advapi32.lib netapi32.lib gdi32.lib user32.lib userenv.lib winspool.lib shell32.lib ole32.lib uuid.lib oleacc.lib ucrt.lib "C:\test\fossil\tcl\main\win\Release_AMD64_VC1944\tclstub.lib" "C:\test\fossil\tcl\main\win\Release_AMD64_VC1944\tcl91.lib"  -stack:2300000 C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\tk_Dynamic\winMain.obj C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\tk_Dynamic\wish.res C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\tkstub.lib C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\tcl9tk91.lib
Code wird generiert.
Codegenerierung ist abgeschlossen.
        if exist C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\wish91.exe.manifest mt -nologo -manifest C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\wish91.exe.manifest -outputresource:C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\wish91.exe;1
Building Tk library zip file
/usr/bin/rmdir: `/S': Permission denied
/usr/bin/rmdir: `/Q': No such file or directory
/usr/bin/rmdir: `C:\\test\\fossil\\tk\\6a9bae5e-demo-dist-nmake\\win\\Release_AMD64_VC1944\\libtk.vfs\\tk_library\\demos': Directory not empty
NMAKE : fatal error U1077: "rmdir /S /Q "C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\libtk.vfs\t
k_library\demos"": Rückgabe-Code "0x1"
Stop.

The following folder exists and is non-empty if I look to the file system:

C:\test\fossil\tk\6a9bae5e-demo-dist-nmake\win\Release_AMD64_VC1944\libtk.vfs\tk_library\demos

Sorry, this does the right thing but does not work.

Why are ther double-backslashes? This is not TCL code...

Thanks for all, Harald