使用 Pyinstaller 创建可执行文件 Pygame 后出错
Error after creating executable Pygame with Pyinstaller
所以我的 pygame 脚本在 python 中运行完美,所以我决定尝试使用 Pyinstaller 捆绑该程序以便分发它。我按照指示编译和 运行 Pyinstaller:
sudo pip install pyinstaller
pyinstaller Loop.py
它运行良好。然后我 运行 生成的可执行文件来查看它的运行情况:
cd /dist/Loop/
./Loop
结果是这样的:
Fatal Python error: (pygame parachute) Segmentation Fault
Aborted (core dumped)
似乎没有执行任何一行 Loop.py,因为导入包后的第一行是打开一个新的 window(这并没有发生)。通过一点谷歌搜索,似乎唯一推荐的解决方案是调试代码以找到分段发生的位置。但是,这没有意义,因为代码本身运行良好,它仅在使用 pyinstaller 后才执行此操作。我什至在Loop可执行文件的同一目录下输入了一个python shell,验证导入pygame没有问题。
无论如何,我只是在寻找一种方法来捆绑 python 项目。当然,如果您知道捆绑 python 项目进行分发的更好方法(在 Ubuntu 16 上使用 Python 2.7),我很乐意查看 :)
编辑
我创建了一个尽可能简化的代码版本,以便专注于主要问题(当然也是为了证明问题是可重现的)。这是主程序(Loop.py
):
from Car import*
vehicle = Car()
def display_all(main_surface, display_list):
main_surface.fill((0, 100, 100))
for element in display_list:
element.display(main_surface)
def update_all(update_list):
for element in update_list:
element.update()
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
None
key = pygame.key.get_pressed()
to_update = [vehicle]
to_display = [vehicle]
update_all(to_update)
display_all(main_s, to_display)
pygame.display.flip()
这里是 Car.py
:
from Startup import*
class Car:
def __init__(self):
self.body = pygame.image.load("Images//Body//Grey.png")
self.wheels = pygame.image.load("Images//Wheels//Black.png")
self.rect = self.body.get_rect()
self.rect.x = width/2
self.rect.y = height/2
self.rect.center = self.rect.x, self.rect.y
self.angle = 0
self.move_x = 0
self.move_y = 0
def display(self, main_surface):
temp_image = pygame.transform.rotate(self.body, self.angle)
main_surface.blit(temp_image, (self.rect.x, self.rect.y))
temp_image = pygame.transform.rotate(self.wheels, self.angle)
main_surface.blit(temp_image, (self.rect.x, self.rect.y))
def update(self):
self.move_x = 0
self.move_y = 0
这里是 Startup.py
:
import pygame
import math
pygame.font.init()
clock = pygame.time.Clock()
font = pygame.font.SysFont("", 20)
pygame.init()
width = 1000
height = 600
main_s = pygame.display.set_mode((width, height))
再次编辑
我刚刚按照评论中的建议尝试了py2app
,但似乎没有用。正如我在 the only documentation 中看到的那样,我的意图是在 MacOS 上成为 运行。如上所述,我使用的是 Ubuntu 16,这就是我编写代码的架构。当我完成上面链接的教程时,我没有遇到任何困难,并继续执行文件:
./dist/Loop.app/Contents/MacOS/Loop
然后我立即得到了错误:
bash: cannot execute binary file: Exec format error
这似乎表明它不适用于我的计算机。
您是否知道是否有适用于 Ubuntu 的版本?或者是否有其他解决方案?
谢谢,
内森
感谢您提供了一个合适的例子,它帮助我找出了罪魁祸首:
font = pygame.font.SysFont("", 20)
如果您禁用该行,您应该能够构建并 运行 您的可执行文件。这很容易测试,因为您的示例中未使用 font
。
搜索 non-existent 字体似乎有问题,如果您将名称更改为可能可用的名称,如 Arial
,或包含一个列表作为 documentation states。或者您可以从可用的字体中指定一种字体,例如pygame.font.get_fonts()[0]
。
这里有一个修改过的例子,可以让汽车向你点击鼠标的任何地方移动:
import pygame
import math
pygame.init()
pygame.font.init()
all_fonts = pygame.font.get_fonts()
print(all_fonts)
font = pygame.font.SysFont(all_fonts[0], 20) # just use the first font.
#font = pygame.font.SysFont("Arial, couriernewm", 20)
clock = pygame.time.Clock()
width = 1000
height = 600
main_s = pygame.display.set_mode((width, height))
class Car(pygame.sprite.Sprite):
"""Sprite with self drawn images"""
def __init__(self, speed=5):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((40,30)).convert_alpha() # sprites need an 'image'
self.image.fill((0,0,0,0)) # make transparent
pygame.draw.rect(self.image, (111,111,111), (0,5, 40, 15)) # draw the body
for center in [(5,5), (35,5), (5,20), (35, 20)]: # draw four wheels
pygame.draw.circle(self.image, (0,0,0), center, 5)
self.rect = self.image.get_rect()
self.rect.x = width/2
self.rect.y = height/2
self.rect.center = self.rect.x, self.rect.y
self.angle = 0
self.move_x = 0
self.move_y = 0
self.speed = speed
self.destination = self.rect.center
def update(self, pos=None):
if pos:
#set new destination
self.destination = pos
else:
# move towards destination at speed
xd = self.destination[0] - self.rect.center[0]
if xd < 0:
xd = max(xd, -self.speed)
else:
xd = min(xd, self.speed)
yd = self.destination[1] - self.rect.center[1]
if yd < 0:
yd = max(yd, -self.speed)
else:
yd = min(yd, self.speed)
self.rect.center = (self.rect.center[0] + xd, self.rect.center[1] + yd)
# create a sprite group to store cars
slow_car = Car()
vehicles = pygame.sprite.Group(slow_car)
running = True
#main loop
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
pass
elif event.type == pygame.MOUSEBUTTONDOWN:
# move to position
vehicles.update(event.pos)
# update sprites
vehicles.update()
# clear surface
main_s.fill((0, 100, 100))
#draw sprites
vehicles.draw(main_s)
# update display
pygame.display.update()
clock.tick(10)
pygame.quit()
注意:不幸的是,这不是 运行ning 在 Mac 上,所以我不能保证它会工作。启动可执行文件时我确实看到应用程序失败。
所以我的 pygame 脚本在 python 中运行完美,所以我决定尝试使用 Pyinstaller 捆绑该程序以便分发它。我按照指示编译和 运行 Pyinstaller:
sudo pip install pyinstaller
pyinstaller Loop.py
它运行良好。然后我 运行 生成的可执行文件来查看它的运行情况:
cd /dist/Loop/
./Loop
结果是这样的:
Fatal Python error: (pygame parachute) Segmentation Fault
Aborted (core dumped)
似乎没有执行任何一行 Loop.py,因为导入包后的第一行是打开一个新的 window(这并没有发生)。通过一点谷歌搜索,似乎唯一推荐的解决方案是调试代码以找到分段发生的位置。但是,这没有意义,因为代码本身运行良好,它仅在使用 pyinstaller 后才执行此操作。我什至在Loop可执行文件的同一目录下输入了一个python shell,验证导入pygame没有问题。
无论如何,我只是在寻找一种方法来捆绑 python 项目。当然,如果您知道捆绑 python 项目进行分发的更好方法(在 Ubuntu 16 上使用 Python 2.7),我很乐意查看 :)
编辑
我创建了一个尽可能简化的代码版本,以便专注于主要问题(当然也是为了证明问题是可重现的)。这是主程序(Loop.py
):
from Car import*
vehicle = Car()
def display_all(main_surface, display_list):
main_surface.fill((0, 100, 100))
for element in display_list:
element.display(main_surface)
def update_all(update_list):
for element in update_list:
element.update()
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
None
key = pygame.key.get_pressed()
to_update = [vehicle]
to_display = [vehicle]
update_all(to_update)
display_all(main_s, to_display)
pygame.display.flip()
这里是 Car.py
:
from Startup import*
class Car:
def __init__(self):
self.body = pygame.image.load("Images//Body//Grey.png")
self.wheels = pygame.image.load("Images//Wheels//Black.png")
self.rect = self.body.get_rect()
self.rect.x = width/2
self.rect.y = height/2
self.rect.center = self.rect.x, self.rect.y
self.angle = 0
self.move_x = 0
self.move_y = 0
def display(self, main_surface):
temp_image = pygame.transform.rotate(self.body, self.angle)
main_surface.blit(temp_image, (self.rect.x, self.rect.y))
temp_image = pygame.transform.rotate(self.wheels, self.angle)
main_surface.blit(temp_image, (self.rect.x, self.rect.y))
def update(self):
self.move_x = 0
self.move_y = 0
这里是 Startup.py
:
import pygame
import math
pygame.font.init()
clock = pygame.time.Clock()
font = pygame.font.SysFont("", 20)
pygame.init()
width = 1000
height = 600
main_s = pygame.display.set_mode((width, height))
再次编辑
我刚刚按照评论中的建议尝试了py2app
,但似乎没有用。正如我在 the only documentation 中看到的那样,我的意图是在 MacOS 上成为 运行。如上所述,我使用的是 Ubuntu 16,这就是我编写代码的架构。当我完成上面链接的教程时,我没有遇到任何困难,并继续执行文件:
./dist/Loop.app/Contents/MacOS/Loop
然后我立即得到了错误:
bash: cannot execute binary file: Exec format error
这似乎表明它不适用于我的计算机。
您是否知道是否有适用于 Ubuntu 的版本?或者是否有其他解决方案?
谢谢, 内森
感谢您提供了一个合适的例子,它帮助我找出了罪魁祸首:
font = pygame.font.SysFont("", 20)
如果您禁用该行,您应该能够构建并 运行 您的可执行文件。这很容易测试,因为您的示例中未使用 font
。
搜索 non-existent 字体似乎有问题,如果您将名称更改为可能可用的名称,如 Arial
,或包含一个列表作为 documentation states。或者您可以从可用的字体中指定一种字体,例如pygame.font.get_fonts()[0]
。
这里有一个修改过的例子,可以让汽车向你点击鼠标的任何地方移动:
import pygame
import math
pygame.init()
pygame.font.init()
all_fonts = pygame.font.get_fonts()
print(all_fonts)
font = pygame.font.SysFont(all_fonts[0], 20) # just use the first font.
#font = pygame.font.SysFont("Arial, couriernewm", 20)
clock = pygame.time.Clock()
width = 1000
height = 600
main_s = pygame.display.set_mode((width, height))
class Car(pygame.sprite.Sprite):
"""Sprite with self drawn images"""
def __init__(self, speed=5):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((40,30)).convert_alpha() # sprites need an 'image'
self.image.fill((0,0,0,0)) # make transparent
pygame.draw.rect(self.image, (111,111,111), (0,5, 40, 15)) # draw the body
for center in [(5,5), (35,5), (5,20), (35, 20)]: # draw four wheels
pygame.draw.circle(self.image, (0,0,0), center, 5)
self.rect = self.image.get_rect()
self.rect.x = width/2
self.rect.y = height/2
self.rect.center = self.rect.x, self.rect.y
self.angle = 0
self.move_x = 0
self.move_y = 0
self.speed = speed
self.destination = self.rect.center
def update(self, pos=None):
if pos:
#set new destination
self.destination = pos
else:
# move towards destination at speed
xd = self.destination[0] - self.rect.center[0]
if xd < 0:
xd = max(xd, -self.speed)
else:
xd = min(xd, self.speed)
yd = self.destination[1] - self.rect.center[1]
if yd < 0:
yd = max(yd, -self.speed)
else:
yd = min(yd, self.speed)
self.rect.center = (self.rect.center[0] + xd, self.rect.center[1] + yd)
# create a sprite group to store cars
slow_car = Car()
vehicles = pygame.sprite.Group(slow_car)
running = True
#main loop
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
pass
elif event.type == pygame.MOUSEBUTTONDOWN:
# move to position
vehicles.update(event.pos)
# update sprites
vehicles.update()
# clear surface
main_s.fill((0, 100, 100))
#draw sprites
vehicles.draw(main_s)
# update display
pygame.display.update()
clock.tick(10)
pygame.quit()
注意:不幸的是,这不是 运行ning 在 Mac 上,所以我不能保证它会工作。启动可执行文件时我确实看到应用程序失败。