88
99import argparse
1010import glob
11- import io as cStringIO
1211import os
13- import pathlib
1412import re
1513import shutil
1614import sys
1715import sysconfig
1816import time
1917from collections import defaultdict
18+ from itertools import chain
19+ from pathlib import Path
2020from subprocess import PIPE , Popen
2121
2222import numpy
2626from setuptools .command .install import install
2727
2828# non-empty DEBUG variable turns off optimization and adds -g flag
29- DEBUG = bool ( os .getenv ("DEBUG" , "" ) )
29+ DEBUG = os .getenv ("DEBUG" , False )
3030WIN = sys .platform .startswith ("win" )
3131MAC = sys .platform .startswith ("darwin" )
3232
@@ -47,76 +47,39 @@ def create_all(generated_dir, pymoldir="."):
4747 create_buildinfo (generated_dir , pymoldir )
4848
4949
50- class openw (object ):
51- """
52- File-like object for writing files. File is actually only
53- written if the content changed.
54- """
55-
56- def __init__ (self , filename ):
57- if os .path .exists (filename ):
58- self .out = cStringIO .StringIO ()
59- self .filename = filename
60- else :
61- os .makedirs (os .path .dirname (filename ), exist_ok = True )
62- self .out = open (filename , "w" )
63- self .filename = None
64-
65- def close (self ):
66- if self .out .closed :
67- return
68- if self .filename :
69- with open (self .filename ) as handle :
70- oldcontents = handle .read ()
71- newcontents = self .out .getvalue ()
72- if oldcontents != newcontents :
73- self .out = open (self .filename , "w" )
74- self .out .write (newcontents )
75- self .out .close ()
76-
77- def __getattr__ (self , name ):
78- return getattr (self .out , name )
79-
80- def __enter__ (self ):
81- return self
82-
83- def __exit__ (self , * a , ** k ):
84- self .close ()
85-
86- def __del__ (self ):
87- self .close ()
88-
89-
90- def create_shadertext (shaderdir , shaderdir2 , outputheader , outputfile ):
91- outputheader = openw (outputheader )
92- outputfile = openw (outputfile )
50+ def create_shadertext (
51+ shader_dir : str ,
52+ shader_dir2 : str ,
53+ output_header_file_name : str ,
54+ output_file_name : str ,
55+ ):
56+ varname = "_shader_cache_raw"
9357
9458 include_deps = defaultdict (set )
9559 ifdef_deps = defaultdict (set )
60+ shader_dir_path = Path (shader_dir )
61+ shader_dir2_path = Path (shader_dir2 )
62+ extension_regexp = "*.[gs][vs][fs][shared][tsc][tse]"
9663
9764 # get all *.gs *.vs *.fs *.shared from the two input directories
98- shaderfiles = set ()
99- for sdir in [shaderdir , shaderdir2 ]:
100- for ext in ["gs" , "vs" , "fs" , "shared" , "tsc" , "tse" ]:
101- shaderfiles .update (
102- map (os .path .basename , sorted (glob .glob (os .path .join (sdir , "*." + ext ))))
103- )
104-
105- varname = "_shader_cache_raw"
106- outputheader .write ("extern const char * %s[];\n " % varname )
107- outputfile .write ("const char * %s[] = {\n " % varname )
108-
109- for filename in sorted (shaderfiles ):
110- shaderfile = os .path .join (shaderdir , filename )
111- if not os .path .exists (shaderfile ):
112- shaderfile = os .path .join (shaderdir2 , filename )
65+ shaderfiles = set (
66+ chain (
67+ shader_dir_path .glob (extension_regexp ),
68+ shader_dir2_path .glob (extension_regexp ),
69+ )
70+ )
11371
114- with open (shaderfile , "r" ) as handle :
115- contents = handle .read ()
72+ with (
73+ open (output_header_file_name , "w" ) as output_header ,
74+ open (output_file_name , "w" ) as output_file ,
75+ ):
76+ output_header .write (f"extern const char * { varname } [];\n " )
77+ output_file .write (f"const char * { varname } [] = {{\n " )
11678
117- if True :
118- outputfile .write ('"%s ", ""\n ' % ( filename ) )
79+ for filename in shaderfiles :
80+ output_file .write (f'" { filename . name } ", ""\n ' )
11981
82+ contents = filename .read_text ()
12083 for line in contents .splitlines ():
12184 line = line .strip ()
12285
@@ -125,52 +88,43 @@ def create_shadertext(shaderdir, shaderdir2, outputheader, outputfile):
12588 continue
12689
12790 # write line, quoted, escaped and with a line feed
128- outputfile .write (
129- '"%s\\ n"\n ' % line .replace ("\\ " , "\\ \\ " ).replace ('"' , r"\"" )
130- )
91+ escaped_line = line .replace ("\\ " , "\\ \\ " ).replace ('"' , r"\"" )
92+ output_file .write (f'"{ escaped_line } \\ n"\n ' )
13193
13294 # include and ifdef dependencies
13395 if line .startswith ("#include" ):
13496 include_deps [line .split ()[1 ]].add (filename )
13597 elif line .startswith ("#ifdef" ) or line .startswith ("#ifndef" ):
13698 ifdef_deps [line .split ()[1 ]].add (filename )
13799
138- outputfile .write (",\n " )
139-
140- outputfile .write ("0};\n " )
141-
142- # include and ifdef dependencies
143- for varname , deps in [("_include_deps" , include_deps ), ("_ifdef_deps" , ifdef_deps )]:
144- outputheader .write ("extern const char * %s[];\n " % varname )
145- outputfile .write ("const char * %s[] = {\n " % varname )
146- for name , itemdeps in deps .items ():
147- outputfile .write ('"%s", "%s", 0,\n ' % (name , '", "' .join (sorted (itemdeps ))))
148- outputfile .write ("0};\n " )
149-
150- outputheader .close ()
151- outputfile .close ()
100+ output_file .write (",\n " )
101+ output_file .write ("0};\n " )
152102
153-
154- def create_buildinfo (outputdir , pymoldir = "." ):
155- try :
156- sha = (
157- Popen (["git" , "rev-parse" , "HEAD" ], cwd = pymoldir , stdout = PIPE )
158- .stdout .read ()
159- .strip ()
160- .decode ()
161- )
162- except OSError :
163- sha = ""
164-
165- with openw (os .path .join (outputdir , "PyMOLBuildInfo.h" )) as out :
166- print (
167- """
168- #define _PyMOL_BUILD_DATE %d
169- #define _PYMOL_BUILD_GIT_SHA "%s"
170- """
171- % (time .time (), sha ),
172- file = out ,
173- )
103+ # include and ifdef dependencies
104+ for varname , deps in [
105+ ("_include_deps" , include_deps ),
106+ ("_ifdef_deps" , ifdef_deps ),
107+ ]:
108+ output_header .write (f"extern const char * { varname } [];\n " )
109+ output_file .write (f"const char * { varname } [] = {{\n " )
110+ for name , item_deps in deps .items ():
111+ item_deps = '", "' .join (sorted (item_deps ))
112+ output_file .write (f'"{ name } ", "{ item_deps } ", 0,\n ' )
113+ output_file .write ("0};\n " )
114+
115+
116+ def create_buildinfo (output_dir_path : str , pymoldir : str = "." ):
117+ output_dir = Path (output_dir_path )
118+ sha_raw = Popen (["git" , "rev-parse" , "HEAD" ], cwd = pymoldir , stdout = PIPE ).stdout
119+ sha = sha_raw .read ().strip ().decode () if sha_raw is not None else ""
120+
121+ info_file = output_dir / "PyMOLBuildInfo.h"
122+ info_file .write_text (
123+ f"""
124+ #define _PyMOL_BUILD_DATE { time .time ()}
125+ #define _PYMOL_BUILD_GIT_SHA "{ sha } "
126+ """
127+ )
174128
175129
176130# handle extra arguments
@@ -302,7 +256,6 @@ def guess_msgpackc():
302256
303257
304258class CMakeExtension (Extension ):
305-
306259 def __init__ (
307260 self ,
308261 name ,
@@ -336,15 +289,15 @@ def run(self):
336289 self .build_cmake (ext )
337290
338291 def build_cmake (self , ext ):
339- cwd = pathlib . Path ().absolute ()
292+ cwd = Path ().absolute ()
340293
341294 # these dirs will be created in build_py, so if you don't have
342295 # any python sources to bundle, the dirs will be missing
343296 name_split = ext .name .split ("." )
344297 target_name = name_split [- 1 ]
345- build_temp = pathlib . Path (self .build_temp ) / target_name
298+ build_temp = Path (self .build_temp ) / target_name
346299 build_temp .mkdir (parents = True , exist_ok = True )
347- extdir = pathlib . Path (self .get_ext_fullpath (ext .name ))
300+ extdir = Path (self .get_ext_fullpath (ext .name ))
348301 extdirabs = extdir .absolute ()
349302
350303 extdir .parent .mkdir (parents = True , exist_ok = True )
@@ -394,7 +347,7 @@ def concat_paths(paths):
394347
395348 if WIN :
396349 # Move up from VS release folder
397- cmake_lib_loc = pathlib . Path (
350+ cmake_lib_loc = Path (
398351 lib_output_dir , "Release" , f"{ target_name } { shared_suffix } "
399352 )
400353 if cmake_lib_loc .exists ():
@@ -487,7 +440,7 @@ def make_launch_script(self):
487440 launch_script = os .path .join (self .install_scripts , launch_script )
488441
489442 python_exe = os .path .abspath (sys .executable )
490- site_packages_dir = sysconfig .get_path (' purelib' )
443+ site_packages_dir = sysconfig .get_path (" purelib" )
491444 pymol_file = self .unchroot (
492445 os .path .join (site_packages_dir , "pymol" , "__init__.py" )
493446 )
@@ -701,8 +654,6 @@ def make_launch_script(self):
701654 libs += [
702655 "opengl32" ,
703656 ]
704- # TODO: Remove when we move to setup-CMake
705- ext_comp_args += ["/std:c++17" ]
706657
707658if not (MAC or WIN ):
708659 libs += [
@@ -816,7 +767,7 @@ def get_packages(base, parent="", r=None):
816767
817768if WIN :
818769 # pyconfig.py forces linking against pythonXY.lib on MSVC
819- py_lib = pathlib . Path (sysconfig .get_paths ()["stdlib" ]).parent / "libs"
770+ py_lib = Path (sysconfig .get_paths ()["stdlib" ]).parent / "libs"
820771 lib_dirs .append (str (py_lib ))
821772
822773ext_modules += [
0 commit comments